Does DataTemplate in the resources set the datacontext of the view automatically? - c#

in my window resources i have a datatemplate like the following
<DataTemplate DataType="{x:Type ViewModels:GoogleViewModel}">
<Views:GoogleView/>
</DataTemplate>
does that mean if i bind the content of a UI elemnt to that view model it will load the view and set the datacontext of that view to the view model automatically, or i still have to set the datacontext for the view?

Yes that will set the dataContext of the Viewmodel to the View Automatically. Always DataContext set to View not to the viewModel. That means Object of the ViewModel will be bind to the View not the other way.

Related

Accessing a static property of a view model is null

in my app I need to call a method in my main view model from a sub settings view model to change a tab control in the main view. Basically its a list of viewsmodels in a tab control. The settings viewmodel has checkboxes to turn tabs on or off.
Anyway, I setup a static property in the main viewmodel of the instance. In my settings viewmodel constructor I get a null response but if I retrieve the instance on each checkbox property change it works. Seems like a timing issue on when the instances are created. Is there an event or something that can tell me when the main viewmodel instance isn't null?
<Window.Resources>
<DataTemplate DataType="{x:Type skyTelescope:SkyTelescopeVM}">
<skyTelescope:SkyTelescopeV />
</DataTemplate>
<DataTemplate DataType="{x:Type rotator:RotatorVM}">
<rotator:RotatorView />
</DataTemplate>
<DataTemplate DataType="{x:Type focuser:FocuserVM}">
<focuser:FocuserView />
</DataTemplate>
<DataTemplate DataType="{x:Type settings:SettingsVM}">
<settings:SettingsV />
</DataTemplate>
</Window.Resources>
There's a lot to learn with wpf and the mvvm approach is very different from event driven code.
Your markup looks like you're doing viewmodel first... or something like that.
If you have a MainWindowViewModel exposes say a SubVM property.
Bind SubVM to the content property of a contentcontrol in mainwindow.
Set SubVM to an instance of a viewmodel such as SettingsVM.
This is then templated out in the view using the matching datatemplate.
You see a SettingsV appear.
The datacontext of SettingsV is your SubVM.
Bind controls in SettingsV to properties in SubVM and the values can transfer between them.
That allows you to control when you instantiate SettingsVM in MainWindowViewModel.
You therefore "know" whether you have an instance of it or not.
You can cache instances of viewmodels in a dictionary.
Use a type as your key and you can instantiate one if you don't have it in your dictionary, then re-use it if you wanted to retain state.
You can make MainWindow instantiate MainWindowViewModel by defining it's datacontext in xaml.
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
With viewmodel first there's an oddity with the way templating works. If you wanted to reset (unbound) view state then you need to force the re-templating by setting your SubVM property null first.
This command takes a Type as a parameter
private RelayCommand<Type> navigateCommand;
public RelayCommand<Type> NavigateCommand
{
get
{
return navigateCommand
?? (navigateCommand = new RelayCommand<Type>(
vmType =>
{
CurrentViewModel = null;
CurrentViewModel = Activator.CreateInstance(vmType);
}));
}
}
Obviously, this doesn't stash any instance of a vm away in a dictionary, it's just instantiating every time.

how to get TextBlock value inside resource dictionary

I'm new to WPF and I have following text-block in resource dictionary
<TextBlock x:Name="textSampleVal" Text="{Binding textSamVal}" />
How to get this textSampleVal value from ViewModel class
How to get this textSampleVal value from ViewModel class
Simply by accessing the textSampleVal property that the TextBlock binds to.
It doesn't make any difference whether you define the binding in a ResourceDictionary or a view, the TextBlock will still bind to the textSamVal property of its DataContext and this is supposed to be the view model.
A view model never "gets" anything from the view, i.e. the view model doesn't know anything about any TextBlock elements. The view updates the view model using data bindings.

MVVM DataTemplate and non-empty view model constructor

I have the below DataTemplate:
<DataTemplate DataType="{x:Type vm:MyViewModel}">
<views:MyView/>
</DataTemplate>
The thing is, my view model has a constructor that takes parameters which are automatically injected by the container (unity). In order for the DataTemplate to work though, MyViewModel needs to have a paramaterless constructor.
Is there any other way I can inject the appropriate values into my view model if I am using a DataTemplate to create it?
I don't think Views should be creating ViewModels.
ViewModels should be creating other ViewModels, and the View simply defines how to draw the ViewModel.
For example, a ParentViewModel might have a property called ChildViewModel. The ParentView will contain a ContentControl which has its Content bound to ChildViewModel, and a DataTemplate would be used to tell the application to draw ChildViewModel as a ChildView.
With that being said, how is your View currently creating your ViewModel? You could always add DependencyProperties to your View and build your ViewModel in the View's loaded event using these properties.
You might want to consider using an MVVM framework such as Caliburn.Micro, and take a ViewModel first approach.

Multiple DataContext in a View vs MVVM? Is that right?

I have the following problem: I'm building a chat WPF application on which I want the user to be connected with different accounts to GTalk. I've made a ViewModel that permits handling the communication but I don't know which is the best way to handle DataContext. I think that I need different DataContexts for every connection instance but I don't know if this is the right way and don't know how to define multiple DataContexts in a View.
A DataContext provides the default binding source for an element in the view. It is inherited from parent to child within the visual tree. You can change the DataContext for any element by binding it to some property of its parent DataContext. This is a common way of creating 'islands' that bind to a child view model.
For example, if you have a User view model that has an Address Property, you can render this in an AddressUserControl as follows:
<StackPanel>
... elements bound to properties of User ...
<AddressUserControl DataContext="{Binding Address}"/>
</StackPanel>
If you have a variable number of accounts, you can use the ItemsControl.
The rough idea behind this: You can bind the ItemsControl to a list of "Sub-ViewModels" in your main ViewModel and define a DataTemplate (= a View) for each of them. The DataContext of each DataTemplate is automatically assigned to a corresponding item in your ViewModel's list.

How do I Encapsulate a WPF ViewModel/View UserControl as a Control

I've built a WPF UserControl View/ViewModel pair: the view XAML handles the layout and bindings, and the ViewModel handles the logic, in-line with the recommended MVVM pattern.
I would like to be able to re-use this as a control.
How do I hide/encapsulate the ViewModel associated with the view, so that I can use the control as I would a standard control [such as a button] ?
i.e. How do I hide the control's viewmodel ?
depends on how you bind ViewModel class to the control.
if you do like this:
YourControl()
{
DataContex = new ViewModel();
}
then I don't see any problems. add reference to your control and use it.
You can create your ViewModel as a StaticResource within your XAML. The problem with setting the DataContext to your ViewModel is that you can't use that you can no longer use your DataContext from the window or page you in which you use the control.
In your XAML declare your ViewModel:
<myNS:MyViewModel x:Key="ViewModel />
Reference your view model within your XAML:
<TextBlock Text="{Binding Source={StaticResource ViewModel}, Path=TextToBind}" />
In your Code Behind you can access and initialize quickly, I usually make a property for easy reference to my view model.
private MyViewModel viewModel
{
get { return this.Resources["ViewModel"] as MyViewModel; }
}

Categories