【问题标题】:Change type of control based on type of item source?根据项目来源类型更改控件类型?
【发布时间】:2021-04-29 03:17:09
【问题描述】:

我正在使用 MVVM 设计模式,我想根据项目源对象的类型更改要使用的控件类型。 我的项目来源类型代码:

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
}

在我的视图模型中,我将属性列表绑定到 xaml

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

此集合包含StringValuePropertyItemVMComboBoxPropertyItemVM 两种类型的对象。

现在我想要实现的是,根据我想决定 xaml 是否包含 TextBoxComboBox 的对象类型。

我的 xaml 代码:

<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>

在一些帮助下,我发现我可以为这两种类型提供不同的数据模板并在它们之间切换,但是我找不到如何做到这一点。谁能帮我解决这个问题?

【问题讨论】:

标签: c# wpf xaml user-interface mvvm


【解决方案1】:

自动数据模板选择

将数据模板移动到ItemsControl 资源并分配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>

ItemsControl会根据类型自动选择合适的数据模板。

数据模板选择器

虽然在这种情况下您不需要它,但对于更复杂的情况(例如基于视图模型的条件),您可以实现 DataTemplateSelector,如下所示:

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

然后您将使用键在范围内的资源字典中定义数据模板。

<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>

最后,您可以将选择器的一个实例分配或引用到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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多