I have a wizard created in WPF consisting of pages as UserControl
objects. What I'm trying to do is to load plugins from .DLL files which contain the following:
I've been able to successfully load in and instantiate the UserControl
object as well as the View Model, and I have gotten to the stage where the Control appears in it's own wizard page as intended.
(This is probably the view model that's instantiated correctly, since I set the title for the wizard page in the view model and that all works fine)
The problem I'm getting is that the UserControl
I've loaded from the DLL isn't displaying correctly. Instead of displaying the UserControl
contents, it just shows the plaintext MyDLL.MyCustomUserControl
from the line x:Class="MyDLL.MyCustomUserControl"
where the actual user control should be.
The contents of my user control that I'm loading from the DLL is:
<UserControl x:Class="MyDLL.MyCustomUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<Label Content="This is the Plugin Options Page" />
<TextBox Text="{Binding Path=PluginStringText}" />
</StackPanel>
</UserControl>
The property PluginStringText
exists in the View Model for this User Control
.
I have a feeling I need to somehow assign or bind the View Model to the User Control after loading it in from the DLL. As part of my wizard, there is a section where I define Data Templates (this is another UserControl which contains the Wizard's pages), but I don't know how to actually add extra templates during runtime. I have a feeling this is causing the issue.
Searching through many topics reveals I could probably do this through the code behind file for the view, but then I have no way of obtaining a reference to the view's code behind in the first place to call a method. Is there a way of adding a new DataTemplate entry from the View's View Model class?
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModel:ExistingPage1ViewModel}">
<view:ExistingPage1View />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:ExistingPage2ViewModel}">
<view:ExistingPage2View />
</DataTemplate>
<...>
Thanks in advance if someone could point me in the right direction
I found a way to resolve this. The problem was as I had expected, there was no mapping between the ViewModel data type and the View in which to render the ViewModel with.
I discovered a useful guide here http://www.ikriv.com/dev/wpf/DataTemplateCreation/ which explains how to create a new data template within code, very similar to if you'd hard coded the template in the XAML.
This was all well and good, but I still had to find a way to call the method to create the data template.
Well - It turned out I didn't need to call the method at all in the code behind! I just put the method to create the data template directly in my view model which is responsible for populating the wizard's pages.
This also has the added benefit that I do not have to hard code my existing pages datatemplate's in the xaml.
I will add the code referenced at http://www.ikriv.com/dev/wpf/DataTemplateCreation/ for future reference:
The method to create the DataTemplate
object:
DataTemplate CreateTemplate(Type viewModelType, Type viewType)
{
const string xamlTemplate = "<DataTemplate DataType=\"{{x:Type vm:{0}}}\"><v:{1} /></DataTemplate>";
var xaml = String.Format(xamlTemplate, viewModelType.Name, viewType.Name, viewModelType.Namespace, viewType.Namespace);
var context = new ParserContext();
context.XamlTypeMapper = new XamlTypeMapper(new string[0]);
context.XamlTypeMapper.AddMappingProcessingInstruction("vm", viewModelType.Namespace, viewModelType.Assembly.FullName);
context.XamlTypeMapper.AddMappingProcessingInstruction("v", viewType.Namespace, viewType.Assembly.FullName);
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
context.XmlnsDictionary.Add("vm", "vm");
context.XmlnsDictionary.Add("v", "v");
var template = (DataTemplate)XamlReader.Parse(xaml, context);
return template;
}
This DataTemplate
then needs to be registered as an application resource:
Registering the DataTemplate:
Application.Current.Resources.Add(template.DataTemplateKey;, template);
Once again, this code was provided thanks to Ivan Krivyakov at http://www.ikriv.com/dev/wpf/DataTemplateCreation/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With