Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
88 views
in Technique[技术] by (71.8m points)

c# - Change type of control based on type of item source?

I am working with MVVM design pattern where I want to change the type of control to be used based on the type of item source object. My code for item source types :

public class PropertyItemVM : ViewModelBase
{
   // Some base code for all basic  property items
}

public class StringValuePropertyItemVM : PropertyItemVM
{
   // Code to correctly create string value property item
}

public class ComboBoxPropertyItemVM : PropertyItemVM
{
   // Code to correctly create combo box property item
}

In my view model I have property list binded to xaml as

public ObservableCollection<PropertyItemVM> Properties { get; set; }

This collection contains both the types of objects StringValuePropertyItemVM and ComboBoxPropertyItemVM.

Now what I want to achieve is, based on type of object I want to decide whether the xaml will contain a TextBox or a ComboBox.

My xaml code :

<StackPanel>
    <!--Items Control containing all list of properties to be shown-->
    <ItemsControl x:Name="Local" ItemsSource="{Binding Properties}" Background="White">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="100"/>
                        <ColumnDefinition Width="100"/>
                    </Grid.ColumnDefinitions>

                    <Label Content="{Binding Label}" 
                           IsEnabled="{Binding IsEnabled}"
                           Grid.Column="0"/>
                    <!-- Here based on type need to change the TextBox with ComboBox-->
                    <TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                             Grid.Column="1"
                             IsEnabled="{Binding IsEnabled}"/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

With some help I found out I can have different data templates for both types and switch among those, however I can't find how to do that. Can anyone help me with how can this be achieved ?

question from:https://stackoverflow.com/questions/65882710/change-type-of-control-based-on-type-of-item-source

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Automatic Data Template Selection

Move the data templates to the ItemsControl resources and assign a DataType.

<StackPanel>
   <!--Items Control containing all list of properties to be shown-->
   <ItemsControl x:Name="Local" ItemsSource="{Binding Properties}" Background="White">
      <ItemsControl.Resources>
         <DataTemplate DataType="{x:Type local:StringValuePropertyItemVM}">
            <Grid>
               <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="100"/>
                  <ColumnDefinition Width="100"/>
               </Grid.ColumnDefinitions>

               <Label Content="{Binding Label}" 
                      IsEnabled="{Binding IsEnabled}"
                      Grid.Column="0"/>
               <!-- Here based on type need to change the TextBox with ComboBox-->
               <TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        Grid.Column="1"
                        IsEnabled="{Binding IsEnabled}"/>
            </Grid>
         </DataTemplate>
         <DataTemplate DataType="{x:Type local:ComboBoxPropertyItemVM}">
            <ComboBox/>
         </DataTemplate>
      </ItemsControl.Resources>
   </ItemsControl>
</StackPanel>

The ItemsControl will automatically select the right data template based on the type.

Data Template Selector

Although you do not need it in this case, for more complex cases (e.g. conditions based on the view model), you could implement a DataTemplateSelector, like this:

public class PropertyDataTemplateSelector : DataTemplateSelector
{
   public override DataTemplate SelectTemplate(object item, DependencyObject container)
   {
      if (!(container is FrameworkElement frameworkElement))
         return null;

      switch (item)
      {
         case StringValuePropertyItemVM _:
            return (DataTemplate)frameworkElement.FindResource("StringValuePropertyItemVMDataTemplate");
         case ComboBoxPropertyItemVM _:
            return (DataTemplate)frameworkElement.FindResource("ComboBoxPropertyItemVMDataTemplate");
         default:
            return null;
      }
   }
}

Then you would define the data templates in a resource dictionary in scope with keys.

<DataTemplate x:Key="StringValuePropertyItemVMDataTemplate" DataType="{x:Type local:StringValuePropertyItemVM}">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="100"/>
         <ColumnDefinition Width="100"/>
      </Grid.ColumnDefinitions>

      <Label Content="{Binding Label}" 
             IsEnabled="{Binding IsEnabled}"
             Grid.Column="0"/>
      <!-- Here based on type need to change the TextBox with ComboBox-->
      <TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
               Grid.Column="1"
               IsEnabled="{Binding IsEnabled}"/>
   </Grid>
</DataTemplate>
<DataTemplate x:Key="ComboBoxPropertyItemVMDataTemplate" DataType="{x:Type local:ComboBoxPropertyItemVM}">
   <ComboBox/>
</DataTemplate>

Finally, you would assign or reference an instance of the selector to the ItemsControl.

<StackPanel>
   <!--Items Control containing all list of properties to be shown-->
   <ItemsControl x:Name="Local" ItemsSource="{Binding Properties}" Background="White">
      <ItemsControl.ItemTemplateSelector>
         <local:PropertyDataTemplateSelector/>
      </ItemsControl.ItemTemplateSelector>
   </ItemsControl>
</StackPanel>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...