Selecting the usercontrol to the relating datatemplate in mvvm - wpf

I have lets say a WeeklyViewUserControl.xaml and a DailyViewUserControl.xaml.
Normally I used stuff like this to switch content:
<DataTemplate DataType="{x:Type ViewModel:LessonPlannerViewModel}">
<View:LessonPlannerDailyUC/>
</DataTemplate>
This worked so far. But now I have still the WeeklyViewUC which uses 90 % of the LessonPlannerViewModel code so I want to make this additionally:
<DataTemplate DataType="{x:Type ViewModel:LessonPlannerViewModel}">
<View:LessonPlannerWeeklyUC/>
</DataTemplate>
but this can not work, because from where does the ContentControl
know that VM (LessonPlannerViewModel) should display a DailyViewUC or a WeeklyViewUC ?
<ContentControl Content="{Binding VM}" />
This is my further scenario:
The DailyViewUC has a Button "Weekly View" which is executed via Command="{...}" to the Command in the LessonPlannerViewModel.
The WeeklyViewUC has a Button "Daily View"...
Depending on what button is pressed the datatemplate should somehow choose the appropriate UserControl to display!
How can I do that?

You can create a DataTemplateSelector and assign it to the ContentTemplateSelector property of the ContentControl.

Related

connect View to ViewModel with DataTemplate

I'm trying to understand. When I'm connecting View to ViewModel like this:
<DataTemplate DataType="{x:Type local:MyViewModel}">
<local:MyView />
</DataTemplate>
What does it mean?
It looks like the View is set to be the DataTemplate of the ViewModel. BUT the ViewModel doesn't have a Property of DataTemplate. So what exactly is going on in there?
A demonstration of the question - How do I do that by code (Connecting the View and ViewModel this specific way. I can't write ViewModel.DataTemplate = View)?
Thank you.
It means "To whatever control whose Content data is MyViewModel place MyView there". You are not setting DataTemplate of viewmodel (That does not mean anything) you are setting the DataTemplate for the control whose Data is MyViewModel.
Take for example an ItemsControl with an Items Source of
ObservableCollection<Employee> Employees
where each Employee is represented by a DataTemplate for Example :
<DataTemplate TargetType="{x:Type local:Employee}">
<StackPanel>
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text="{Binding LastName}" />
</StackPanel>
</DataTemplate>
So in the same manner a MyViewModel.cs such as Employee.cs as a visual representation based on a DataTemplate .
and represented for example as such :
<ContentControl Content="{Binding MyViewModelProperty}" />
The way how it works is very simple. Your definition of DataTemplate is something like a definition of how a data will look like. In your example the data that you want to represent visually are of type:
DataType="{x:Type local:MyViewModel}"
By defining DataTemplate in control, window or other resources, e.g.
<UserControl.Resources> ...your template... <UserControl.Resources>,
you say "Hey, I want that all my data of type local:MyViewModel will look like this...". Inside the template you define a root control, that will be put in all places where your local:MyViewModel have been used. Normally when you place local:MyViewModel in Grid, ContentControl or other containers, you will see its string representation like "xxxx.xxxxx.MyViewModel" instead of visual.
To to see a graphical representation you must define a DataTemplate. It will replace the string "xxxx.xxxxx.MyViewModel" - representing your data and put there a visual control you defined in the template. Then when it is done, this representation - control from your DataTemplate will get DataContext property set to your View Model, here it will be local:MyViewModel instance.
That will give you a possibility to use binding in your DataTemplate, to bind in you DataTemplate directly to properties from you ViewModel.
Is that more clear now?

Place a ContentControl inside a custom control XAML

I created a custom control and what to use a ContentControl inside that control for use of the MVVM design pattern however my control does not like this when I run the application. For testing I also tried other standard controls but none of them work inside the custom control... just more custom controls that are dependant on the parent custom control.
Does anybody suggest how to place standard controls such as the ContentControl inside a custom control?
Cheers.
EDIT
XamlParseException -> 'Add value to collection of type
'System.Collections.ObjectModel.ObservableCollection(Ribbon_Framework.RibbonTabItem)'
threw an exception.' Line number '8' and line position '14'.
<Ribbon:Ribbon AutomaticStateManagement="True" x:Name="Ribbon">
<ContentControl x:Name="SearchRibbon" Content="{Binding Path=SearchRibbon}" ContentTemplate="{DynamicResource SearchRibbonTemplate}" />
</Ribbon:Ribbon>
Inside the contentcontrol ->
<DataTemplate x:Key="SearchRibbonTemplate">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ribbon:RibbonTabItem Header="Search">
<Ribbon:RibbonGroupBox Header="{Binding Path=DisplayName}" Width="100">
<Ribbon:Button Width="100" Icon="{Binding Path=TemplateResource}" LargeIcon="{Binding Path=TemplateResource}" Command="{Binding Path=Commands}" />
</Ribbon:RibbonGroupBox>
</Ribbon:RibbonTabItem>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
Your Ribbon control expects an object of RibbonTabItem type (since it houses an
ObservableCollection<RibbonTabItem>
so you can only add the RibbonTabItem class to it - you need to make sure your control allows other elements inside it. Some 3rd party controls get round this by providing a content control inside the inner item of their custom control (i.e. let RibbonTabItem have a ContentControl inside it) or allow you to customise the item template
You need to change your implementation of Ribbon or change the functionality of RibbonTabItem for this to work. Look at ItemsControl.Items property and see what type that is. You should try using that type for your ObservableCollection

SL ItemsControl, command on ViewModel not firing from ItemsControl (CheckBox)

I'm using PRISM v2, CAL, SL4 and MVVM and have a delegate command on my ViewModel called CheckCommand. The ItemsControl contains a checkbox and I'm trying to get the items in ItemsControl/Checkbox to fire this command when it's checked - but it's not communication back to the viewmodel!
I think it's because each items 'datacontext' is the individual object the item is bound to, rather than the ViewModel?
- My suspicion is actually correct, cause if I move my DelegateCommand out of the viewmodel and into the class defining the items in itemscontrol I can see the commands/methods beeing fired!
View:
<ListBox x:Name="BasketListBox" ItemsSource="{Binding BasketCollection}" MinWidth="200">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox commands:Checked.Command="{Binding CheckCommand}" IsChecked="False" </CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
Can anyone point me in the right direction please?
Cheers, Mcad.
EDIT 1:
The commanding now works, see solution below. BUT, I now run into another problem:
"An exception occurred while creating a region with name 'basketRegion'. The exception was: System.InvalidOperationException: ItemsControl's ItemsSource property is not empty. This control is being associated with a region, but the control is already bound to something else. If you did not explicitly set the control's ItemSource property, this exception may be caused by a change in the value of the inherited RegionManager attached property"
Created seperate question for this problem to make it more clean:
PRISM-MVVM, ItemsControl problem with View injection
You want every CheckBox to fire the same command? You could:
<CheckBox commands:Checked.Command="{Binding DataContext.CheckCommand, ElementName=BasketListBox}"
Or you could have every child view model expose the command via their own property.
Thanx Kent. You put me on the right path to solve this, ended up doing this:
<ListBox x:Name="basketListBox" ItemsSource="{Binding basketcollection}" MinWidth="200">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox commands:Checked1.Command="{Binding DataContext.CheckCommand, ElementName=basketListBox}" Content="{Binding basketName}"> </CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>

How do I bind a generic window to an arbitrary view model at runtime, using DataTemplates?

I have a large number of ViewModel classes. For each of these classes, there is a corresponding .xaml file which is a 'UserControl'. In my App.xaml, I have them registered as DataTemplates, like so:
<DataTemplate DataType="{x:Type viewModel:MainMenuViewModel}">
<view:MainMenuView/>
</DataTemplate>
With the idea being that WPF will be able automatically swap in the necessary user controls at runtime. For example, this works:
<Grid>
<StackPanel>
<TextBlock Text="SuperApp" />
<ItemsControl>
<ViewModels:MainMenuViewModel/>
</ItemsControl>
</StackPanel>
</Grid>
In that the entry "MainMenuViewModel" is automatically replaced by the MainMenuView, bound to the MainMenuViewModel. Great. My current goal is now this: I want to have a button, on, say, a view embedded in the MainMenuView, which opens a popup window, which will have a new ViewModel inside. The idea is to set it up so that I have a single 'generic' popup form, in which I embed an arbitrary ViewModel, and let WPF handle actually rendering it with DataTemplates, similar to the above. So I have a command bound to a button, like so:
<Button Command="{Binding Path=LaunchInStandaloneForm}" Content="Rip Out"/>
Which successfully creates a new window, sets the dataContext equal to the appropriate ViewModel, and shows the window.
The question is: How do I set up the XAML of this popup window so that it will render the appropriate DataTemplate for the ViewModel which is the DataContext? I've tried:
<Grid>
<ItemsControl ItemsSource="{Binding Path=.}">
</ItemsControl>
</Grid>
, but it comes up blank. Any pointers?
To set the ItemsSource to the DataContext, use ItemsSource={Binding}. That assumes that the DataContext is an enumerable collection of your View Model objects.
Updating with correct answer:
Use a ContentControl :)
Hope that helps.
The accepted answer here shows how to change templates at runtime. You should be able to dig out the answer from that. Any questions just shout.
How to modify silverlight combobox data display
Hope that helps

Is it Possible to apply a DataTemplate to a Page?

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.

Resources