Hi,
the easiest way is to encapsulate the generic class. Try following demo:
XAML MainWindow:
Window x:Class="WpfApp1.Window034"
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:local="clr-namespace:WpfApp034"
xmlns:view="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel>
<Button Content="Switch" Command="{Binding}" Width="200" Margin="5"/>
<view:Window034UC1 DataContext="{Binding CurrentVM}"/>
</StackPanel>
</Window>
ViewModel:
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
namespace WpfApp034
{
public class ViewModel : ICommand, INotifyPropertyChanged
{
public object CurrentVM { get; set; } = new WpfControlLibrary034.MyViewModel1();
public void Execute(object parameter)
{
if (CurrentVM is WpfControlLibrary034.MyViewModel2)
{
WpfControlLibrary034.MyViewModel1 vm = new WpfControlLibrary034.MyViewModel1();
vm.Data.Info1 = DateTime.Now.ToString("mm:ss.fff");
CurrentVM = vm;
}
else
{
WpfControlLibrary034.MyViewModel2 vm = new WpfControlLibrary034.MyViewModel2();
vm.Data.Info2 = DateTime.Now.ToString("mm:ss.fff");
CurrentVM = vm;
}
OnPropertyChanged(nameof(CurrentVM));
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => true;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
UserControl with DataTemplates
<UserControl x:Class="WpfControlLibrary1.Window034UC1"
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"
xmlns:local="clr-namespace:WpfControlLibrary1"
xmlns:view="clr-namespace:WpfControlLibrary034"
xmlns:vm="clr-namespace:WpfControlLibrary034"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate DataType="{x:Type vm:MyViewModel1}">
<view:MyViewModel1View DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MyViewModel2}">
<view:MyViewModel2View DataContext="{Binding}"/>
</DataTemplate>
</UserControl.Resources>
<ContentControl Content="{Binding}"/>
</UserControl>
And classes:
using System;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfControlLibrary034
{
public class MyViewModel1 : MyViewModel<ModelData1> { }
public class MyViewModel2 : MyViewModel<ModelData2> { }
public class MyViewModel<T>
{
private T d;
public T Data
{
get
{
if (d == null) d = (T)Activator.CreateInstance(typeof(T));
return d;
}
}
}
public class ModelData1 { public string Info1 { get; set; } }
public class ModelData2 { public string Info2 { get; set; } }
public class MyViewModel1View : UserControl
{
public MyViewModel1View()
{
StackPanel stp = new StackPanel();
this.Content = stp;
stp.Children.Add(new Label() { Content = "1. View" });
Label lbl = new Label();
lbl.SetBinding(Label.ContentProperty, new Binding("Data.Info1"));
stp.Children.Add(lbl);
}
}
public class MyViewModel2View : UserControl
{
public MyViewModel2View()
{
StackPanel stp = new StackPanel();
this.Content = stp;
stp.Children.Add(new Label() { Content = "2. View" });
Label lbl = new Label();
lbl.SetBinding(Label.ContentProperty, new Binding("Data.Info2"));
stp.Children.Add(lbl);
}
}
}