Get DataContext From XAML - c#

I deleted the CodeBehind of my MainWindow.xaml, cause I'm doing a small project where I literally must do that.
So I'm creating an instance of my ViewModel in this way over xaml:
<Grid.DataContext>
<lib:StartPageViewModel />
</Grid.DataContext>
Well now, I need this DataContext in my Code (StartPageViewModel), as I want to open an other solution (For more Informations take a look here).
Any Ideas, on how I can get this DataContext?

At least I solved the problem.
Actually I didn't really need to use the DataContext for this:
public static DTE2 GetDTE(DataContext dataContext)
{
ICustomTypeDescriptor typeDescriptor = dataContext as ICustomTypeDescriptor;
Debug.Assert(typeDescriptor != null, "Could not get ICustomTypeDescriptor from dataContext. Was the Start Page tool window DataContext overwritten?");
PropertyDescriptorCollection propertyCollection = typeDescriptor.GetProperties();
return propertyCollection.Find("DTE", false).GetValue(dataContext) as DTE2;
}
I changed the code to the following, it works now perfectly, I can open Solutions without using the DataContext:
public static DTE2 GetDTE()
{
return (DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
}

A ViewModel shouldn't know anything about the View.
So when applying 'proper' MVVM, you shouldn't be trying to get to the DataContext from within the ViewModel.
The code of the StartPageViewModel IS part of the object that is put in the DataContext. This means that you can access the object by using this in the code of the ViewModel.
If you are looking for the Grid (or even higher up the VisualTree) you could pass it using a property in the Xaml:
<Grid Name="MyGrid">
<Grid.DataContext>
<lib:StartPageViewModel MyParent={Binding ElementName=MyGrid} />
</Grid.DataContext>
</Grid>
Still, if you do that, you are adding knowledge about the View to the ViewModel.

I've never declared a viewmodel in a XAML file, but have you tried:
viewName.DataContext as ViewModelType;
BTW, deleting the code-behind is usually a good practice.

Related

Custom XAML Binding SOURCE Class

I am trying to find a better way to declare the ViewModel a UWP XAML Page uses.
At this moment,
I declare a ViewModel class ViewModelClass that contains my data properties.
Then I declare an instance of that class as StaticResource of the Page. I like calling those VIEW for consistency across all my Page designs.
Finally, I declare the Page's DataContext as a Binding to the StaticResource VIEW.
This yields a page that understands what data structure is in use and allows AutoComplete when working Bindings. Nice, though lots of lines of same-old-same-old code.
Only, it is not really suitable to ViewModels as the declared resource is a static resource. It is instantiated when the page is instantiated. Most pages will receive a ViewModel parameter upon NavigatedTo, which cannot be used to replace the static resource, because it is, well. static.
So I end up changing the Page's DataContext upon navigation from the initial reference to VIEW to the ViewModel instance I actually want to use.
Big caveat is to declare the back-reference to the page's DataContext when deep in the bowels of a Master-Detail situation is rather horrible. Imagine a collection whose display is in part depending on a Master's property.
How do you tie back robustly to the DataContext of the page from anywhere inside the page?
I have tried giving the page a Name (PAGE for simplicity) and then using ElementName=PAGE, Path=DataContext.someProperty. Ugly, plus you lose all information of the class represented by DataContext.
Another approach is to create a Wrapper around the actual ViewModel called StaticViewModel that has only one property: public ViewModel viewModel. Now I can declare the wrapper as a StaticResource, and tell the page's top-level FrameworkElement to use VIEW.viewModel as its DataContext. Works, and reliably, but sooooo ackward and cumbersome.
I would LOVE to implement a SOURCE class for bindings called PageDataContext that would do nothing else but to loop into the page and get the DataContext from there.
Imagine: {Binding someProperty, Source={PageDataContext}
How would I go about declaring said Source class for a UWP app???
I would LOVE to implement a SOURCE class for bindings called PageDataContext that would do nothing else but to loop into the page and get the DataContext from there. Imagine: {Binding someProperty, Source={PageDataContext}
For your requriment, you could implement your viewmodel in the page Resources and give it x:key. When you bind the property of viewmodel you could access this viewmodel with x:key Source={StaticResource ViewModel} for more please refer the following code.
ViewModel
public class ViewModel
{
public ViewModel()
{
Visibility = false;
}
public bool Visibility { get; set; }
}
Xaml
<Page.Resources>
<local:ViewModel x:Key="ViewModel" />
</Page.Resources>
<TextBlock
Width="100"
Height="44"
Text="{x:Bind Name}"
Visibility="{Binding Visibility, Source={StaticResource ViewModel}}" />
Well, no dice so far.
Working with all those options I found that the best one is a Wrapper class that can be assigned to a static resource which in turn is the basis for the page's DataContext. The wrapped instance of the actual ViewModel is then assigned during OnNavigatedTo() and used as the DataContext of the basic FrameworkElement of the page.
Brr, so much verbose code.
STILL WONDERING how to implement a different version of a source directive. Is there no way to declare one's own Source for a Data Binding? Is this stuff really hard-coded into the framework???

WPF: Cannot get View to change dynamically using DataTemplate

I have a problem designing my WPF application. I cannot get the Views to change dynamically. The code to call another View is contained in the Views themselves. (I am trying to implement the MVVM pattern. I do not want any code behind in the View xaml files other than assigning the DataContext. An exception is made in the xaml file of the MainWindow).
Basically, I have a Window that contains a UserControl. The UserControl is my View and it is connected to another class serving as ViewModel through Datacontext.
What I want to do is to dynamically change this View/ViewModel pairs contained in the Window.
My idea was define a static property in the ViewModel of the MainWindow and store the ViewModel of the current View in it. Then I planned to use DataTemplates to automatically load a new View whenever a new ViewModel is stored in the static property.
I decided to use a static property because the code to load another ViewModel is contained in the ViewModels itself and I needed a central point with access from everywhere.
So far so good. My initial View loads and displays correctly.
However, pressing a button in that View to load the next View fails although the new ViewModel is correctly assigned to the static property.
I tried several things.
I defined DataTriggers within the ContentControl to react to changes in the static property. No help.
Implementing INotifyProperty and DependencyProperty failed in the end because of the static nature of the property (or I did something wrong).
I just can’t get it to work.
Do you have any ideas why this would be?
Do you have an idea how I could solve my general problem of dynamically displaying Views without using a static property in my MainWindow. I believe this is causing problems and I have a notion that I am not using the most elegant method. (I do want to maintain the concept of each View holding the code to load any other View)
This is a code fragment from the MainWindow:
<UserControl>
<UserControl.Resources>
<DataTemplate DataType="{x:Type vm:StartViewModel}">
<v:StartView></v:StartView>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:OverviewViewModel}">
<v:OverviewView></v:OverviewView>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl Content="{Binding ActiveViewModel}">/ContentControl>
</Grid>
</UserControl>
Code behind:
DataContext = new MainViewModel();
MainViewModel contains the definition for the property ActiveViewModel. The constructor for the class is static. All ViewModels inherit from BaseViewModel class:
private static BaseViewModel activeViewModel;
static public BaseViewModel ActiveViewModel
{
get { return activeViewModel; }
set { activeViewModel = value; }
}
Thanks a lot for your help.
Bye,
Eskender

Data binding to custom UserControl

So, I have made my own subclass of UserControl, called ChildView (I really can't come up with a decent name), that I want to show inside a container in a window, I have many different kinds of these UserControls and the window must be capable of showing all of them. The UserControls have implemented my subclass like this:
<src:ChildView x:Class="(namespace).LoginView" [...]>
public partial class LoginView : ChildView
And I have tried to add it to my window like so:
<Grid x:Name="ViewHolder" Grid.Column="1" Grid.Row="1">
<src:ChildView DataContext="{Binding CurrentView}" />
</Grid>
private ChildView _currentView;
public ChildView CurrentView
{
get { return _currentView; }
set
{
if (_currentView == value)
return;
_currentView = value;
smLog.Trace("View set to {0}", value.GetType().Name);
NotifyPropertyChanged("CurrentView");
}
}
However, this does not work. Nothing is shown in my container when I set CurrentView. There are no error messages in the output that would indicate a problem with the binding. Other data bindings in the window works. I can use my ChildViews by specifying their classes directly in the XAML, i.e:
<Grid x:Name="ViewHolder" Grid.Column="1" Grid.Row="1">
<src:LoginView />
</Grid>
I've read some about dependency properties but I don't think I need one here? I did try to implement one anyway but it didn't seem to help, though I probably made some mistake, I couldn't quite wrap my head around it...
So I guess my question is; do I need a dependency property? If so, how do I implement it in this case? If not, what is the problem?
Changing the Child's DataContext won't matter, you're trying to change the control itself, not the data it's bound to. What you need to do is add a placeholder control that would contain the actual view. WPF has such a thing built in, take a look at ContentControl.
Change your grid so it'll containt a ContentControl instead of ChildView, and bind the view to the control's Content property
<Grid>
<ContentControl Content="{Binding CurrentView}"/>
</Grid>

Why does binding to a DepenencyProperty on a user control use the user control's Data Context?

Say I have a WPF application (exe) that has this in the MainWindow.xaml:
<Grid>
<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}"/>
<extraControls:MyUserControl MyDependencyProperty="{Binding Something}" />
</Grid>
and my MainWindow.xaml.cs looks like this:
public MainWindow()
{
DataContext = new MainWindowVM();
InitializeComponent();
}
And my MainWindowVM.cs has a property setup for Something that notifies on property changed.
The user controls are made in a separate dll. As you may guess, MyMVVMUserControl has the DataContext set to a view model.
public MyMVVMUserControl()
{
DataContext = new MyMVVMUserControlVM();
InitializeComponent();
}
MyUserControl does not have a DataContext set in the code behind.
So the interesting thing is that they both have MyDependencyProperty setup exactly the same.
But the MVVM version does not work.
After digging in a bit, I found that the {Binding Something} in MainWindow.xaml is using the View Model setup for the MyMVVMUserControl as the DataContext (rather than the DataContext set in MainWindow.cs (set to MainWindowVM)).
And my question is why?
Why would WPF look inside the user control and use it's DataContext for a binding that is in the actual application?
(NOTE: I know I can get around this by setting the source in the binding, but I want others to be able to use my user controls. But with this issue, I now have a built-in "gotcha" for anyone I want to use my user controls.)
I think I understand you problem, and I'm gonna to give a solution that works for me (I had this problem before). The think is that seams that you are setting the DataContext for you MyMVVMUserControl in code behind, and then it take the bindings from that.
The solution I found for this, is to set the datacontext in code behind, but not at the user control. Set the datacontext for the UserControl's child item. For instance, supose this is the Xaml of your UserControl:
<UserControl ... x:Name="userControl">
<Grid x:Name="rootContainer">
...
</Grid>
</UserControl>
Then in the code behind set the rootContainer's data context, in this way all visual children can access to the control data context, and also the user control datacontext is empty.
...
rootContainer.DataContext = new UserControlViewModel();
...
Hope this may helps you to solve your issues...
You really shouldn't ever set the DataContext of a UserControl from inside the UserControl. By doing so, you are preventing any other DataContext from getting passed to the UserControl, which defeats one of WPF's biggest advantages of having separate UI and data layers.
WPF objects only inherit their DataContext from the parent object if the DataContext is not set to anything else. When your MyMVVMUserControl is being created, you are setting the DataContext to a new MyMVVMUserControlVM, which prevents the DataContext from being inherited from MainWindow.
So its normal that your MVVMUserControl would have it's DataContext set to your MyMVVMUserControlVM, because you set it explicitly in the UserControl's constructor.
This is by-design. UI objects in WPF/MVVM are only meant to be visual representations of the data layer, so it wouldn't make much sense to set the data layer and then try to bind your properties to something that is not on the data layer.
For example, take this line of code:
<UserControl DataContext="{Binding ClassA}" Content="{Binding Name}" />
This would bind the Content property to UserControl.DataContext.Name, which is ClassA.Name. It wouldn't make much sense if this would result in binding to UserControl.Parent.DataContext.Name, as the binding should refer to to the current object's DataContext, and not the Parent's DataContext.
So the only time I ever set the DataContext of a UserControl from inside the UserControl itself is if the UserControl is its own separate object that is never meant to interact with data from the rest of the application. Which so far has been never :)
Typically my UserControls are almost always one of two things:
Either a visual representation of a ViewModel (or Model), such as a CustomerUserControl for a CustomerViewModel, in which case I pass them the DataContext they need when they get used
For example,
<local:CustomerUserControl DataContext="{Binding SelectedCustomer}" />
or
<DataTemplate DataType="{x:Type local:CustomerModel}">
<local:CustomerUserControl />
</DataTemplate>
Or a self-sustained UI object that receives any external data it needs via custom DependencyProperties, and does any additional logic in the code-behind the control, such as a DatePicker control that has a SelectedDate dependency property, or a CalculatorUserControl with dependency properties for Equation and Value
<local:DatePickerUserControl SelectedDate="{Binding SomeDate}" />
<local:CalculatorUserControl Equation="{Binding SomeString}"
Value="{Binding SomeDouble}" />
In your case, it sounds like you should be using the first case, and should be passing a ViewModel into your UserControl containing the data it needs.
<extraControls:MyMVVMUserControl DataContext="{Binding MyMVVMUserControlVM}"
MyDependencyProperty="{Binding Something}">
or
<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}">
<extraControls:MyMVVMUserControl.DataContext>
<viewModels:MyMVVMUserControlVM />
</extraControls:MyMVVMUserControl.DataContext>
<extraControls:MyMVVMUserControl />

Understanding DataBinding

I'm new to WPF and the whole data binding thing. I read a couple of posts and I'm quite confused about how to bind my data to a UI element.
I saw a post doing it this way:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="myWindow">
<Grid>
<TextBox Text="{Binding Path=Speed, ElementName=myWindow}" />
</Grid>
</Window>
This assumes Speed is a property / member defined in the code-behind file. A few other people named binding using a static resource and reference this one and others named DataContext to be used for binding. Now, because I'm new to WPF's data binding, I'm quite unsure if there exists any best practice method about which data binding to use.
Basically I was wondering why there has to be a several class-property defined as kind of connector to the underlying viewmodel, I though this stuff was more "dynamically".
I'm aiming at only having the XAML file, without the need to add anything into the *.xaml.cs code behind file. For example: I have a class named MainWindowViewModel (which will represent my ViewModel) having a member of the type ObservableCollection<string> and I want to bind a ListBox (in my View) to this collection. The only way I got this working so far was using the the first case, ElementName, where I have to add a property to the view-class as a kind of connector. Just like this:
MainWindow.xaml:
<Window x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="MW" Title="MainWindow" Height="419" Width="463">
<Grid>
<ListBox ItemsSource="{Binding ElementName=MW, Path=ListerResultConnector}" />
</Grid>
</Window>
MainWindow.xaml.cs:
private ObservableCollection<string> mListerResultData = MainWindowViewModel.Instance.RetrievalStringResults;
public ObservableCollection<string> ListerResultConnector
{
get { return mListerResultData; }
}
My question is, if there exists a smarter way to bind data to my UI as using as further "connector" property in the code-behind file.
Your ViewModel should be set as the DataContext to the view. Then you don't need any "further connector" in codebehind. Binding actually refers to DataContext and if you don't set it, it remains as 'this', which corresponds to your codebehind file (which is just a partial to your view).
Also, take a look at: WPF Apps With The Model-View-ViewModel Design Pattern
You should get the WPF and it's binding basics first, but once you understand those, I suggest looking at Caliburn Micro and its convention-based bindings, event handling and other features which make your code much cleaner.
Your {Binding ElementName=MW means you are binding to the Window itself, so your DataContext is the Window, and any properties you implement need to be defined in that Window (in your code behind - your "connectors").
You need to remove the ElementName=MW bit and assign your ViewModel as the DataContext so you can bind to its properties directly. How you do this depends on whether you use "ViewModel First", or "View First"
In View first, you manually assign the DataContext to the View in code when you create the view.
In ViewModel first, you create a DataTemplate in XAML that ties your View to a particular ViewModel. I think ViewModel first is more common. The link that Darjan posted should help you understand the difference.
You should use a separate ViewModel class (WindowViewModel) which represents your data context for your Window (Window.DataContext).
I found that using the MVVM Light toolkit and following some of the videos on the site helped me fill in the gaps. Take time to learn it before getting started and it will start to sink in. IoC containers are also mixed in with MVVM + WPF for directory management & lifetime management of view models and improved design-time experience (blendability).
Toolkits aren't required and sometimes get in your way of learning the pattern. Once you understand it though, you should leverage a toolkit to speedup the development process. Here is a comparison of various MVVM toolkits.
A binding generally has two parts: a source object and a property name
When you specify ElementName in a binding, you are setting the Source object. Other ways to specify the binding's source object include the RelativeSource and Source properties. You can also leave the binding's source object undefined, in which case it will use whatever the DataContext is of the current object. The Source Object can be a UI Element found in WPF's VisualTree, or it can be a class object that is in the control's DataContext
When you specify Path, you are telling the binding what Property to use. You can also leave this property blank to bind to the current object's DataContext
The DataContext is the data object stored behind the control. This is typically a Model or a ViewModel (if using MVVM), although it can also be almost any object, such as a UI Element.
In your example
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="myWindow">
<Grid>
<TextBox Text="{Binding Path=Speed, ElementName=myWindow}" />
</Grid>
</Window>
you are telling the binding that it's Source Object is the UI Element in the Visual Tree named myWindow, and the property is called Speed. Since your object named myWindow is of type Window, this binding will only work if your Window class actually has a property called Speed.
There are a lot of answers here suggesting you switch to using the MVVM design pattern, and I agree that you should try and use MVVM if you're working with WPF. It makes coding a lot simpler since you are separating your application logic from your UI. If you're interested, I have a simple MVVM example posted on my blog which explains the basics of that design pattern.
Yeah, Binding is nothing if not confusing.
This example from msdn may be helpful. Notice how a DataContext is declared at the Window "level" - it's a complex/compound object in this case and Window sub-elements' {Binding} declarations are therefore implicitly relative to the "Parent level" DataContext.
The main goodness we get is that when the DataContext is set to a given object all the "sub element" data bindings are automagically keep in synch. We can control this synchronization at any/many levels in the UI Control structure heirarchy by using this pattern.
Collection binding under the hood
The bottom line is your collection must implement IList as a minimum. Many .NET Collection classes are "binding ready."
Here's a quote from the msnd doc on ObservableCollection:
Before implementing your own collection, consider using ObservableCollection or one of the existing collection classes, such as List, Collection, and BindingList, among many others. If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by index. Implementing IList provides the best performance with the data binding engine.
Finally, IBinding list vs IList is needed for 2-way binding.
The simplest way to do it would be:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:WpfApplication4"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ctrl:MainWindowViewModel x:Key="mym" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource mym}}">
<ListBox ItemsSource="{Binding Path=MyListProp}" />
</Grid>
The example above does the following:
Creates a new object of the ViewModel as resource for you window
Assigns the view model as DataContext for the window (more precisley for the root grid)
Binds the List box to your ViewModel ObservableCollection property MyListProp.
Try to get familiar with the properties of the binding class to fully understand this example by using the msdn library.
Also WPF 4 Unleashed - Adam Nathan is a great resource for a wpf beginner. Chapter 13 - Data Binding should cover everything you might want to know about bindings.

Categories

Resources