Windows 8 Store App Grid DataContext Refresh Programatically - c#

I am setting the GridView Data Context in XAML similar to so:
<Grid x:Name="pageGrid">
<Grid.DataContext>
<local:ViewModel/>
</Grid.DataContext>
</Grid>
This "ViewModel" class is a static class that is fill during:
public MainPage()
{
this.InitializeComponent();
FillViewModel():
}
This allows for the view model to bound on screen load which works.
However, I want to load FillViewModel after the MainPage has initially ran.
Is there a way to programatically refresh the pageGrid XAML databinding? I have to be just missing it.

However, I want to load FillViewModel after the MainPage has initially ran.
Sounds like your looking for the MainWindow / Control "Loaded" Event.
XAML:
<Grid x:Name="Grid1" Loaded="Grid1_Loaded"/>
Code Behind:
private void Grid1_Loaded(object sender, RoutedEventArgs e)
{
// Do Stuff
}

Related

C#/AvaloniaUI - Click a button and change Text

I am very new to AvaloniaUI.
I am really struggling to change a text when I click a button.
Here is my code:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ReadyForWar_Launcher.MainWindow"
Title="ReadyForWar_Launcher">
<StackPanel>
<TextBlock Name="TestBlock">Show my text here!</TextBlock>
<Button Command="{Binding RunTheThing}" CommandParameter="Hello World">Change the Text!</Button>
</StackPanel>
</Window>
Here is my MainWindow.xaml.cs:
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace ReadyForWar_Launcher
{
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void RunTheThing()
{
}
}
}
Inside RunTheThing I don't know how can I select the TextBlock with Name="TestBlock" and change the text to "Hello World".
Can you please help me out on this ?
There are two approaches, the recommended one and straightforward one.
Recommended: Use MVVM pattern. Create a view model with ButtonTextProperty and RunTheThing command, make the command to change the property, assign that model to the DataContext and bind your button text and command to view model properties. The MVVM approach is basically the same as in WPF, so you can use documentation and tutorials from there (that applies to most of the Avalonia, BTW). For example, here is a good one (not advertising, 4th link from google).
Straightforward (aka winforms-way): add x:Name="MyButton" to your button and use this.FindControl<Button>("MyButton") after calling AvaloniaXamlLoader.Load(this);. This will give you a Button reference that you can manipulate from code. Instead of using commands, you can just subscribe to the click handler directly from codebehind, add public void MyButton_OnClick(object sender, RoutedEventArgs args){} to your MainWindow class and add replace Command and CommandParameter with Click="MyButton_OnClick". That way button click will trigger your event handler.
Note, that the second approach doesn't scale well with the application size and suffers from code complexity when handling lists.

How to load a View model when Window or view is loaded

I created a simple application in C# with a view model and usually you have to declare the view model in he datacontext of the window or usercontrol for it to load. Problem is it loads whenever visual studio has the application opened.
I want it to load when the application is running and window is loaded.
<Window x:Class="GraphApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModel="clr-namespace:GraphApp"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<!-- Insert Model view Here. I want it to load when the window is running, not when I have it opened in visual studio.-->
</Window.DataContext>
Is this possible?
Generally, when we want something to happen after an element has loaded, we handle the FrameworkElement.Loaded event:
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
DataContext = new ViewModel();
}
UPDATE >>>
Another way to achieve this would be to set some DataTemplates and have a property of either the type of your view model, or of a common base view model class:
public BaseViewModel ViewModel { get; set; } // Implement INotifyPropertyChanged here
Then in App.xaml Resources:
<DataTemplate DataType="{x:Type ViewModels:FirstViewModel}">
<Views:FirstTrackView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:LastViewModel}">
<Views:LastTrackView />
</DataTemplate>
Then you can implicitly set the DataContext whenever you like in this way and the corresponding view will automatically be displayed:
ViewModel = new SomeViewModel();
Attach to the Window.Loaded event and:
void OnLoad(object sender, RoutedEventArgs e)
{
//Check if the event is not raised by the visual studio designer
if(DesignerProperties.GetIsInDesignMode(this))
return;
//Set the data context:
this.DataContext = //Your viewmodel here
}
I know this is old now, but you can to this by first adding a namespace where your view model is located.
xmlns:vm="clr-namespace:MyWpfForm.ViewModel"
Then add this directly under your closing Window Element
<Control.DataContext>
<vm:MainWindowViewModel />
</Control.DataContext>
where "MainWindowViewModel" is your view model's constructor.

Cannot drag text into a WPF window

I'm trying to set up a WPF window so that it can accept different types of data via Drag and Drop. If I make a new project and set the window to the following:
<Window x:Class="DropShare.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" AllowDrop="True" DragEnter="Window_DragEnter">
<Grid>
</Grid>
</Window>
And set the code-behind to:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Window_DragEnter(object sender, DragEventArgs e)
{
}
}
I only ever get DragEnter firing for files. It never fires for anything else - text, images, etc.
Is there something I'm missing? All the tutorials I've read have seemed to suggest this is all that's needed as the DragEnter event handler let's me state what I accept.
So your code works fine for me. But try this...
In your Window:
<Label Background="Purple" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Drag from here!" MouseDown="Label_MouseDown"/>
and in your code behind:
private void Label_MouseDown(object sender, MouseButtonEventArgs e)
{
DragDrop.DoDragDrop(this, "This is just a test", DragDropEffects.All);
}
Then drag from the label into the window and see if your event fires.
If this works, it may have something to do with the permissions level between Visual Studio and your outside environment (possibly).
See:
https://superuser.com/questions/59051/drag-and-drop-file-into-application-under-run-as-administrator
In WPF drag and drop feature always has to deal with DragDrop Class, Please check here how to do drag and drop across applications

How to manipulate a window object from another class in WPF

I'm new in WPF and C#. I know a lot of VB.NET and I'm used to the way when I call a form object like textboxes, etc. I'm calling it from another form. Now, I'm using WPF, I'm confused. Because I have a Main Window. And I want to add and item to a listbox in the Main Window from a Class. In VB.Net , its just like this.
IN FORM2
Form1.Textbox.Text = "";
Wherein I can't do it in WPF. Can someone please Help me. Thanks!
WPF windows defined in XAML have their controls publicly accessible from other classes and forms, unless you specifically mark them with the x:FieldModifier attribute as private.
Therefore, if you make an instance of your main window accessible in another class, be it a Window or anything else, you'll be able to populate controls from within this second class.
A particular scenario is when you want to update the contents of a control in your main window from a child window that you have opened on top of it. Is such a case, you may set the child window's Owner property to the current, main window, in order to access it while the child is visible. For instance, let's say you have defined these two windows:
// MainWindow
<Window x:Class="TestApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="mainListBox" Height="250" HorizontalAlignment="Stretch" VerticalAlignment="Top"/>
<Button Content="Open Another Window" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="20" Click="OpenAnotherWindow_Click"/>
</Grid>
</Window>
and
// AnotherWindow
<Window x:Class="TestApplication.AnotherWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AnotherWindow" Height="300" Width="300">
<Grid>
<Button Content="Add New Item to Main Window" HorizontalAlignment="Center" VerticalAlignment="Center" Click="AddNewItem_Click"/>
</Grid>
</Window>
each in its own XAML file.
In MainWindow's code behind, inside the button click handler, you show an instance of AnotherWindow as a dialog and set its Owner property to MainWindow's instance:
private void OpenAnotherWindow_Click(object sender, RoutedEventArgs e)
{
AnotherWindow anotherWindow = new AnotherWindow();
anotherWindow.Owner = this;
anotherWindow.ShowDialog();
}
Now, you can access the MainWindow's instance from AnotherWindow's Owner property, in order to add a new item to the ListBox control defined on it, in the button click handler in AnotherWindow's code behind:
private void AddNewItem_Click(object sender, RoutedEventArgs e)
{
MainWindow mainWindow = Owner as MainWindow;
mainWindow.mainListBox.Items.Add(new Random().Next(1000).ToString());
}
It simply adds a new random number to the ListBox, in order to show how the code accesses and modifies the control's data in MainWindow.
Pure WPF solution, but also may be easiest in your case, is using a Data Binding in WPF.
Every form's control is binded to some data on ModelView (pure MVVM approach) or to data (more or less like yuo can do it in WindowsForms). So the "only" thing you have to do is to read/write data binded to controls on UI of that form.
For example, you have TextBox on Windows and want to read a data from it.
This TextBox is binded to some string property of the class that is responsible for holding the data for the controls on that form (just an example, in real world could be 1000 other solutions, based on developer decisions). So what you need, is not to say: "window give textbox" and after read TextBox's content, but simply read binded string property.
Sure it's very simply description of a stuff. But just to give you a hint. Follow databinding link provided above to learn more about this stuff. Do not afraid of a lot of stuff there, it's after all is not a complicated idea and also pretty intuitive. To make that stuff to work in simply case you will not need to make huge efforts by me. The stuff becomes really complex when you end up into real world applications.
This will get all active windows:
foreach (Window item in Application.Current.Windows)
{
}

UserControl calling methods and using variables outside it's class

I have a UserControl that looks like this:
<UserControl x:Class="Test3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Button Name="mybutton" Content="Button Content"/>
</Grid>
</UserControl>
And a main window that uses it like so:
<Window Name="window_main" x:Class="Test3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test3">
<StackPanel>
<Label Name="mylabel" Content="Old Content"/>
<local:UserControl1/>
</StackPanel>
</Window>
What I want to happen, is for mybutton's click event handler to set the content of mylabel to "New Content". However, it appears that this is impossible. Is there in fact a way to do this?
I have chosen to answer this myself since my solution ended up being a bit more complete. I don't fully understand the "right" way to do this, but this is how I did it:
Window1 window_reference = (Window1)(Window1.GetWindow((Button)sender));
After this, the children (such as other xaml controls) of the main window can be seen at compile-time.
Additionally, a more direct way of doing this is to have a public member of the UserControl like so:
namespace UIDD_Test
{
public partial class UserControl1 : UserControl
{
public Window1 window_reference;
public UserControl1()
{
InitializeComponent();
}
}
}
Then whenever appropriate, you can set that member to reference whatever window you want. In my case I have a Window1 class which is derived from Window, so I can set that member of the UserControl1 class like so:
myusercontrol.window_reference = window_main;
Where I've set up the xaml like so:
<local:UserControl1 x:Name="myusercontrol"/>
And window_main is the Name of the main window (it's a Window1 class).
There are several solutions:
The quick and dirty: on mybutton's click event handler, find the parent Window using VisualTreeHelper, then do a ((Label) window.FindName("mylabel")).Content = "New Content".
The clean WPF way: create a new class, add a property object LabelContent and a property ICommand ChangeContentCommand, that will change LabelContent on execution. Set this class as the DataContext of the window, bind the Content of mylabel to LabelContent and the Command property of mybutton to ChangeContentCommand (the user control will inherit the data context).
The simplest way to do what you describe is to take advantage of event routing and just add a handler in the Window XAML:
<StackPanel ButtonBase.Click="Button_Click">
<Label Name="mylabel" Content="Old Content"/>
<local:UserControl1/>
</StackPanel>
and the handler method:
private void Button_Click(object sender, RoutedEventArgs e)
{
mylabel.Content = "New Content";
}
I suspect you probably have some more complications to this in your real application so you may need to do more to verify that the click is coming from the correct button by checking some properties on it.

Categories