WPF implicit DataTemplate declared in App.xaml won't take effect - wpf

In the MainWindow.xaml, I set:
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
In the App.xaml file, I added the following:
<Application.Resources>
<DataTemplate DataType="vm:MainViewModel">
<v:MainView/>
</DataTemplate>
</Application.Resources>
I was hoping the MainWindow will automatically load and show the MainView with its DataContext property set to the windows's one (which was set to MainViewModel at design-time as above), but it won't work - the MainWindow doesn't use the DataTemplate set in App.xaml.
Any better ideas for this scenario?

You should make a minor changes -
First, in your window. Try this:
<Window>
<!-- setup window... -->
<ContentPresenter>
<ContentPresenter.Content>
<vm:MainViewModel/>
</ContentPresenter.Content>
</ContentPresenter>
</Window>
This creates a single content item within your Window. DataTemplates work by mapping content to a new View - in this case, since the Content here is the MainViewModel, it will automatically create and instantiate a new MainView for you. Setting the DataContext will not trigger DataTemplates, since you're never making the ViewModel "content" of an object.
You can shorten this by just setting the Window's Content directly, if you prefer:
<Window>
<Window.Content>
<vm:MainViewModel/>
</Window.Content>
</Window>
Or, even, binding the Content to the DataContext (though this only makes sense if you need the DataContext set for some other purpose):
<Window Content="{Binding}">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
</Window>

I think you need
<DataTemplate DataType="{x:Type vm:MainViewModel}">
EDIT:
I really don't think I'm wrong, the code
<Window.DataContext>
<WpfApplication1:ViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type WpfApplication1:ViewModel}">
<TextBlock>Custom template</TextBlock>
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding}" />
shows “Custom template”. If I remove the x:Type, what's shown instead is “WpfApplication1.ViewModel”, which is the result of calling ToString() on the view model object. This is used in the absence of a DataTemplate.

Related

Associate User Control with ViewModel class

When I define a DataTemplate inline, Visual Studio knows about the type I'm binding to, and properties in that type come up in autocomplete (for example in the code below I was able to select DisplayName from the autocomplete list inside the FirstViewModel template).
<DataTemplate DataType="{x:Type viewmodels:FirstViewModel}">
<StackPanel >
<Label Content="{Binding DisplayName}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:SecondViewModel}">
<views:SecondView/>
</DataTemplate>
However, when the data template references an external control, as for SecondViewModel in the code above, when I'm in the file for the SecondView usercontrol, since it's just a control, the type isn't bound and the editor doesn't help me with anything.
I've tried wrapping my whole control (inside the UserControl element) in the same DataTemplate tag, but then my whole view just shows "System.Windows.DataTemplate".
<UserControl x:Class="Gui.Views.Tabs.ExamsTabViews.ExamInfoView"
xmlns:vm="clr-namespace:Gui.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<DataTemplate DataType="vm:ExamInfoViewModel">
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<!-- contents of the template -->
</DockPanel>
</DataTemplate>
</UserControl>
Is there a way to achieve this kind of binding for the editor?
<DataTemplate DataType="{x:Type viewmodels:SecondViewModel}">
<views:SecondView/>
</DataTemplate>
when this DataTemplate is instantiated, there will be created SecondView and that SecondView will have a SecondViewModel in DataContext. So there is no need any DataTemplate in SecondViewModel control - bind to DataContext instead ({Binding SecondViewModelProperty}). To have design-time support for such binding use d:DataContext="{d:DesignInstance}:
<UserControl d:DataContext="{d:DesignInstance Type=vm:ExamInfoViewModel,
IsDesignTimeCreatable=True}" ...>

How to bind to type Window as a DataTemplate

My WPF application uses a Resource Dictionary. I'm also using MVVM.
I am binding to a ResourceDictionary, but want to bind my MainWindow ViewModel to the MainWindow (of type Window) but MVVM won't let me as MainWindow it's not type UserControl.
<Grid.Resources>
<ResourceDictionary Source="Resources\ResourceDictionary.xaml" />
</Grid.Resources>
<Grid.DataContext>
<Binding Source="{StaticResource Mwvm}" />
</Grid.DataContext>
</Grid>
This means I can't do this
<DataTemplate DataType="{x:Type viewModel:MainWindowViewModel}">
<root:MainWindow x:Key="Mwvm" />
</DataTemplate>
Does any one know how I can do the same thing but when the object is a Window and only using XAML (I know I can do this with code behind in the app.xaml onstartup())?
EDIT
To make this very clear, I know that within my MainWindow I can declare a namespace to my ViewModel, but is this the correct way when the namespace is already referenced in my ResourceDictionary and I'm referencing my ResourceDictionary.
Uhm how about?
<Window>
<Window.DataContext>
<someNs:YourVmClass /> <!-- calls the empty c_tor of the class-->
</Window.DataContext>
</Window>
(I'm not sure, if I understood your question. But I guess, that's what you really want.)
According to your edit:
Sure you could do something like
<!-- Define an instance of your VM in the ResourceDictionary -->
<ResourceDictionary>
<someNs:YourVmClass x:Key="InstOfYourVmClass" />
</ResourceDictionary>
In your view you could do something like this.
<Grid>
<Grid.Resources>
<ResourceDictionary Source="Resources\ResourceDictionary.xaml" />
</Grid.Resources>
<Grid.DataContext>
<StaticResource ResourceKey="InstOfYourVmClass" />
</Grid.DataContext>
</Grid>
But I would strongly recommend not to choose this approach. Problem is, everytime you're referencing this ResourceDictionary the current instance InstOfYourVmClass will be overwritten by a new instantiated version.

Associating View and ViewModel pairs in XAML without repetitive code

I have read a very nice tutorial about letting ViewModels do their stuff while the views just switch themselves via databinding with DataTemplates.
I succesfully made a window which has an ApplicationViewModel, which in turn has a hardcoded DummyViewModel as its CurrentScreen property
<Window x:Class="MyProject.Aplication"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
xmlns:vm="clr-namespace:MyProject.ViewModels"
xmlns:v="clr-namespace:MyProject.Views"
xmlns:System="clr-namespace:System;assembly=mscorlib"
Title="Killer Application" Height="900" Width="1440"
WindowState="Maximized">
<!-- This view has its viewmodel as data context, which has a CurrentScreen property -->
<Window.DataContext>
<vm:AplicationViewModel/>
</Window.DataContext>
<Window.Resources>
<!-- each ViewModel will explicitly map to its current View - while this should happen EXPLICITLY, no? -->
<DataTemplate DataType="{x:Type vm:DummyViewModel}">
<v:DummyView/>
</DataTemplate>
<!-- Doc, are you telling me I'll have to fill this up for EVERY VIEW/VIEWMODEL? -->
<DataTemplate DataType="{x:Type vm:YetAnotherViewModel}">
<v:YetAnotherView/>
</DataTemplate>
</Window.Resources>
<!-- the content is bound to CurrentScreen property of the data context -->
<ContentControl Content="{Binding CurrentScreen}" />
</Window>
I would like to have some (very simple and direct, if possible) way to get the same result WITHOUT having to exhaustively code one DataTemplate Window Resource for every possible screen the window can show. Is there a way?
If you're doing MVVM, then you should be using an MVVM framework. For example, Caliburn.Micro will do view location and automatic binding based on conventions.
I resolved this by using the DataTemplateManager found in this article.
It enables to declare the View-to-ViewModel relation like this:
manager.RegisterDataTemplate<ViewModelA, ViewA>();
manager.RegisterDataTemplate<ViewModelB, ViewB>();
This is still explicit, but it reduces a LOT of overhead of having to do it in XAML. Think about namespaces for instance.

Dynamically load different UserControls based on object type via data binding in xaml

Is there some way in WPF to get the same functionality DataTemplateSelector gives you, but for UserControls?
Say I have a StackView to which I want to bind an IEnumerable of objects. What I'd like to do is somehow have a mapping that, for each object type in the bound IEnumerable, looks at the object type and determines what UserControl to add to the StackView.
So, given three classes:
public class House : Building{}
public class Apartment : Building{}
public class Tent : Building{}
where each class inherits from Building and has its own defined UserControl, I'd like to set DataContext to an IEnumerable<Building> and somehow get the StackView to populate its set of children with the type-specific UserControl.
I'd like to do this with as little code behind as possible. The more data binding and XAML duct tape the better.
You can use complex user controls in a DataTemplate; just declare the DataTemplate as your UserControl.
Example:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="MainWindow" Height="300" Width="300" Name="UI" >
<Window.Resources>
<DataTemplate DataType="{x:Type local:House}" >
<local:HouseUserControl DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Apartment}">
<local:ApartmentUserControl DataContext="{Binding}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding ElementName=UI, Path=ListOfBuildings}" />
</Grid>
</Window>
I'm not sure I see the problem. Just create DataTemplates for each type in your resources somewhere and WPF will use them automatically to render each type.

Use DataTemplate in WPF with a mocked object

I have following xaml code:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding MainWindow, Source={StaticResource Locator}}">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:KeyboardViewModel}">
<vw:Keyboard />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:WelcomeViewModel}">
<vw:Welcome />
</DataTemplate>
</Window.Resources>
<DockPanel>
<DockPanel>
<ContentControl Content="{Binding Path=Workspace}" />
</DockPanel>
</DockPanel>
</Window>
When Workspace is KeyboardViewModel, then the UserControl Keyboard is shown. When Workspace is Welcome, then the Welcome screen is shown. But when I test I mock the ViewModels with Moq. Workspace then get the type IKeyboardViewModelProxyxxxxxxxxxxxxx (where xxxxxxx is a random string), that don't maps to KeyboardViewModel in the DataTemplate and WPF don't now wish DataTemplate to show.
When I use the real KeyboardViewModel, it is no problem.
Can I fix it somehow, or do I have to redesign it?
I'm having a similar issue (without using Moq however). A PARTIAL solution that I used is to inherit both KeyboardViewModel and KeyboardViewModelMock from abstract KeyboardViewModelAbstract. Then you can do:
<DataTemplate DataType="{x:Type vm:KeyboardViewModelAbstract}">
<vw:Keyboard />
</DataTemplate>
Which will work for both, the real model object and the mock.
Unfortunately this solution doesn't scale when you're dealing with models that already have a base class or have any kind of inheritance involved. I'd be great if DataTemplate could be used with interfaces, but they can't.
You can omit the DataType="{x:Type vm:KeyboardViewModel}". If you do that, it is not expecting an instance of type KeyboardViewModel to bind against anymore but only an object of any type that just has all properties that are used in the template.

Resources