Simplified, I have a ResourceDictionary which contains a DataTemplate and a ViewModel-Class.
<ResourceDictionary>
<DataTemplate DataType="Whatever">
<ListBox ItemsSource="{Binding Source={StaticResource MyViewModel}, Path=SomeGlobalData}" />
</DataTemplate>
<MyViewModelClass x:Key="MyViewModel" />
</ResourceDictionary>
Of course the Binding won't work (it'll fire exceptions) because the DataType won't have the resource 'MyViewModel'. But in the VisualTree the "thing" that gets DataTemplated is a child of an object which has the ResourceDictionary merged to its Resources, so there might be a way to access it within runtime.
So my question is: Is there any clean way to access 'MyViewModel' within the DataTemplate?
Your problem is the order these resources are instantiated and the fact that you use StaticResource vs DynamicResource.
A StaticResource provides a value for any XAML property attribute by looking up a reference to an already defined resource. Try to find out more on the subject.
So please move your view model above the data template if you still plan on using StaticResource.
Related
Can someone explain me how the code I am using here can work?
<Window.Resources>
<DataTemplate DataType="{x:Type VM:PBRKEntryViewModel}">
<V:Overview />
</DataTemplate>
<DataTemplate DataType="{x:Type VM:LoginViewModel}">
<V:LoginView />
</DataTemplate>
</Window.Resources>
<Grid>
<ContentPresenter Content="{Binding CurrentView}"/>
</Grid>
My current problems in Details are:
Why can the ContentPresenter present the correct UserControl without Reference to the different DataTemplates? I can see, that ContentPresenter content is bound to my ViewModels CurrentViewProperty but my DataTemplates not?
Another great feature is that the UserControls using the correct ViewModels without a declaration. (Or without a declaration I can see)
I have found this description http://msdn.microsoft.com/en-us/library/System.Windows.Controls.ContentPresenter(v=vs.110).aspx but the remarks section has no answer to this questions. (Or I couldnĀ“t see them...)
Again and just for clarity everything is working perfect, but I do not understand why, so this is just a question to understand the Selection of the template and the Binding.
DateTemplates that specify a DataType property are automatically applied to any instance of that type in the view. It's just a way to tell WPF "every time you need to display this type, use this template"
Your ContentPresenter has its Content bound to some object. If that object type has a matching template, then WPF will use it.
Under the remarks section of the link you posted it's clear enough with this statement:
If there is a DataTemplate associated with the type of Content, the
ContentPresenter applies that DataTemplate to the Content property and
the resulting UIElement and its child elements, if any, are displayed.
Also, if you want to know how dataTemplates are picked automatically, you can read about it here - Data Templating Overview.
Quote from the link:
The DataTemplate class has a DataType property that is very similar to
the TargetType property of the Style class. DataTemplate gets applied
automatically to all objects associated with underlying type.
This is something similar to Styles. If you doesn't specify any x:Key on your Style it will be applied automatically to all child elements falling under the root element where resource is defined.
As soon as you set x:Key on Style, it is no more a default style and will be applied only to the elements explicitly setting style to this resource.
Same holds true for DataTemplate as well. When you specify DataType only, it becomes default template to represent underlying data type. Explicitly specifying x:Key will break this feature.
This is a follow-up to a question posted by Thiado de Arruda. In short, he wanted to have a DataTemplate in his generic.xaml file, but the template wasn't being applied.
The answer given suggested placing the DataTemplate in the ControlTemplate.Resources for the control that hosted his custom type. This works very well, however, suppose that he needed the DataTemplate to apply in other places, not just within the host control. Would it be necessary to copy the DataTemplate to the ControlTemplates of every other host control?
Edit (restating question):
I am developing a WPF application using MVVM design principles. MainWindow.xaml contains the structure of the UI, and all of the styling is coded in Themes\generic.xaml. (The behavior is coded in a separate view model class, but that's irrelevant.) As part of the UI, I created a subclass of ListBox (MyListBoxSubClass) to display a collection of an ordinary .Net object of my own creation (MyObject). MyListBoxSubClass has a style in generic.xaml that redefines the Template property, and it gets applied as expected. I also have a DataTemplate for MyObject in generic.xaml, but this does not get applied. According to the above link, I have to place the DataTemplate in the Resources collection of the ControlTemplate for MyListBoxSubClass in order for this DataTemplate to be applied. This works wonderfully.
My question is how to get the DataTemplate to apply to MyObject everywhere in my application without having to duplicate the DataTemplate? I've tried adding a key to the DataTemplate and referencing it where I need it, but for some reason, I get a XAML parse error at runtime, and Resharper says that it can't resolve my DataTemplate key.
Add the data template in a separate resource dictionary in another XAML file.
Bring the XAML file into your generic.xaml control template resources:
<ControlTemplate ...>
<ControlTemplate.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="wherever.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ControlTemplate.Resources>
</ControlTemplate>
Then wherever else you want to use this data template, you can bring it into merged dictionary of resources of wherever you want - user control, window, another control template, etc...
<Window x:Name="someWindow">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="wherever.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
</Window>
Hope this helps.
I was reading this post and the author makes the suggestion that using DataTemplates to define a ViewModel is a lunatic's way to do it (#7). I do that all the time, is it really that bad?
<DataTemplate DataType="{x:Type local:MyViewModel}">
<Grid>
...
</Grid>
</DataTemplate>
Most of my Views are simply a ResourceDictionary that defines a DataTemplate or two. To me, it makes much better sense to do this than creating a UserControl for every ViewModel. Why would I want the extra layer in WPF's visual tree when it's not needed? And why would I want to take care of mapping ViewModels to Views when a DataTemplate does that for me? Is this syntax really a "lunatics approach"?
Nothing bad about it, except for incredibly large xaml files and the lack of edit support that DataTemplates have on the design surface.
If those issues are hurting you, you can always...
<DataTemplate DataType="{x:Type local:MyViewModel}">
<local:MyViewModelUserControl />
</DataTemplate>
The good thing with DataTemplate is that they are strongly typed to Viewmodel classes. All you need to do is create a ContentPresenter in View and Bind DataContext to VM. If your DataTemplate is defined in a ResourceDictionary and has a DataType attribute instead of Key, WPF will internally figure out the right DataTemplate for the VM class and display it.
But as you mentioned, we cannot create the DataTemplate in a seperate file. So the file where the DataTemplates exist in ResourceDictionary (e.g. App.xaml), the file gets really messy and it becomes difficult to manage the code soon.
So my take is, if the VM is simple create a DataTemplate. Or else it is always better to create a seperate UserControl and bind its content to the VM.
I run into the issue with performance. There is difference between next two case:
1.
<DataTemplate DataType="{x:Type local:MyViewModel}">
<!-- xaml is moved to separate user control -->
<local:MyViewModelUserControl />
</DataTemplate>
2.
<DataTemplate DataType="{x:Type local:MyViewModel}">
<!-- xaml is typed here directly -->
<Border>
...
</Border>
</DataTemplate>
In 1st case it takes longer to render results than in the 2nd. And this difference is in about 2 times.
I posted it as a separate question
I had been setting the DataContext for UserControls like so:
<uc:DepartmentListingView DataContext="{Binding ., Mode=TwoWay}" />
Based on a sample project by Josh Smith I am trying to accomplish the same thing with a DataTemplate and DataType:
<!-- Template applies a DepartmentListingView to an instance of the DepartmentSelectionViewModel class. -->
<DataTemplate DataType="{x:Type model:DepartmentSelectionViewModel}">
<uc:DepartmentListingView />
</DataTemplate>
This works well, but of course there is a problem; I think it might arise from trying to set more than one view (UserControl) to the same view model(?). In the code below I am now associating the same viewModel from above with a different view in the same window.
<DataTemplate DataType="{x:Type model:DepartmentSelectionViewModel}">
<uc:ListSubjectHeaderView />
</DataTemplate>
The first view is wired the same as it was when I set the DataContext explicitly but the last view gets no binding, although no obvious DataBinding error in the console either.
So, would resusing the DataType / DataTemplate trick this way be the problem?
Thanks,
Berryl
Ideally you will have a one to one relationship between a view and viewmodel.
To get what you want perhaps subclass your viewmodel with nothing extra and have that subclassed viewmodel as the datatype in the datatemplate.
That way just creating the correct viewmodel will drive the correct datatemplate and therefore usercontrol
I'm trying to follow the MVVM pattern laid out here: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090097 I have this in my MainWindowResources.xaml file:
<DataTemplate DataType="{x:Type vm:VendorsViewModel}">
<vw:Vendors/> <--- I get a "Can't put a page in a style" error in blend with this
</DataTemplate>
and I've got this in my MainWindow.xaml file
<Window.Resources>
<ResourceDictionary Source="MainWindowResources.xaml"/>
</Window.Resources>
The mainWindow.xaml file contains a menu on the left and page holder on the right. Can I apply a dataTemplate to a <Page>? Or does it have to be a <UserControl>? As it stands, nothing is being data bound, here's what I have on the page that I want to have the viewmodel applied to:
<Custom:DataGrid Margin="0,30,0,0" d:LayoutOverrides="Width" ItemsSource="{Binding Path=AllVendors, Mode=Default}" >
<Custom:DataGrid.Columns>
<Custom:DataGridTextColumn Header="Company Name" Binding="{Binding Path=Name}" />
</Custom:DataGrid.Columns>
</Custom:DataGrid>
DataTemplates are applied to Content, which in most cases is either the Content property of a ContentControl or the Items/ItemsSource property of an ItemsControl. Page is not derived from ContentControl (UserControl is) so a DataTemplate can't be applied to its Content.
From what you're doing here it doesn't sound like that's what you're trying to do though. It looks like you're trying to use a Page in a DataTemplate which is what the error is telling you. Page is treated like Window in that it is a root container that is intended to have visual Content defined in a xaml file. UserControl has a similar purpose but can be inserted anywhere into a layout. If you change vw:Vendors to be a UserControl that should get rid of this specific error but you should also consider whether you're gaining anything from having the UserControl instead of just putting its content directly into the DataTemplate - this can help discourage code-behind and force you to use your ViewModel correctly.