question

essamce avatar image
0 Votes"
essamce asked essamce commented

generic type in xaml

Hi

 <DataTemplate DataType="{x:Type vm:MyViewModel1}">
                 <StackPanel DataContext="{Binding}">
                     <!--template-->
                 </StackPanel>
             </DataTemplate>

the above code works fine except the case of generic class
examples:
MyViewModel2<T>
MyViewModel3<TAcad, TCivil>


i'm using .Net Framework 4.7 Wpf ClassLibrary project
any help will be appreciated, thanks in advance.

windows-wpfdotnet-wpf-xaml
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

PeterFleischer-3316 avatar image
1 Vote"
PeterFleischer-3316 answered essamce commented

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);
     }
   }
 }


· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

hi anonymous user-3316
man, this is cool, i'll accept it as an answer but could you tell me how to use generic in xaml (the hard way as you mentioned)?

0 Votes 0 ·

Hi,
you can use a MarkupExtension like here or here.


1 Vote 1 ·
essamce avatar image essamce PeterFleischer-3316 ·

anonymous user-3316
i think i'll go with the first approach you wrote, anyway thanks a lot sir.

0 Votes 0 ·