如何将 DataTemplateSelector 与 ContentControl 一起使用以根据视图模型显示不同的控件?

How to use DataTemplateSelector with ContentControl to display different controls based on the view-model?

我想创建一个简单的 window,它会根据 selected 的视图模型显示不同的控件(SpinEditTextEdit)。

我已经完成了它背后的代码和逻辑,剩下的就是显示控件(SpinEditTextEdit)本身。

XAML:

   <dx:DXWindow.Resources>

      <DataTemplate x:Key="DataTemplate_Value">
         <dxe:SpinEdit Height="23" MinWidth="200" Width="Auto"
                       Text="{Binding Path=Value, Mode=TwoWay}"
                       Mask="{Binding Mask, Mode=OneWay}" 
                       MaxLength="{Binding Path=InputLength}" />

      </DataTemplate>

      <DataTemplate x:Key="DataTemplate_Text">
         <dxe:TextEdit Height="23" MinWidth="200" Width="Auto"
                       Text="{Binding Path=Value, Mode=TwoWay}"
                       MaskType="RegEx" Mask="{Binding Mask, Mode=OneWay}"
                       MaxLength="{Binding Path=InputLength}"/>
      </DataTemplate>

      <local:PropertyDataTemplateSelector  x:Key="templateSelector"
         DataTemplate_Value="{StaticResource DataTemplate_Value}"
         DataTemplate_Text="{StaticResource DataTemplate_Text}" />

   </dx:DXWindow.Resources>



  <Grid>
      <Grid.RowDefinitions>
         <RowDefinition Height="Auto" />
         <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>

      <StackPanel Grid.Row="0" >
         <Label x:Uid="Label" MinHeight="24" MinWidth="60" Content="Value" />
         <ContentControl ContentTemplateSelector="{StaticResource templateSelector}" />
      </StackPanel>

      <StackPanel Grid.Row="1" x:Uid="OKCancel_Buttons" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom">
         <Button Height="23" x:Name="OK_Button" Click="OK_Click" Content="OK" IsDefault="True" HorizontalAlignment="Right" MinWidth="95" />
         <Button Height="23" x:Name="Cancel_Button" Click="Cancel_Click" Content="Cancel" HorizontalAlignment="Right" MinWidth="95" />
      </StackPanel>

<ContentControl> 中我想 select 将显示哪个控件(SpinEdit 用于数字,TextEdit 用于 names/letters)

C#:

   public class PropertyDataTemplateSelector : DataTemplateSelector
   {
      public DataTemplate DataTemplate_Value { get; set; }
      public DataTemplate DataTemplate_Text { get; set; }

      public override DataTemplate SelectTemplate(object item, DependencyObject container)
      {
         var selector = item as TInputBaseVM;

         if(selector is TInputValueVM)
            return DataTemplate_Value;
         return DataTemplate_Text;
      }
   }

我想 return 基于在 c++/cli 代码中创建的视图模型的特定 DataTemplate

C++/cli:

  TInputValueVM ^oExchange_Value;
  TInputTextVM ^oExchange_Text;

  int inputFormat = A_Attributes.GetInputFormat();

  if(inputFormat)
     oExchange_Text = gcnew TInputTextVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
        A_Attributes.GetInputLength(), gcnew System::String(A_Attributes.GetInitialText()));
  else
     oExchange_Value = gcnew TInputValueVM(gcnew System::String(A_Attributes.GetTitle()), gcnew System::String(A_Attributes.GetMask()),
        A_Attributes.GetInputLength(), A_Attributes.GetInitialValue());

  Dialogs::TSignalNumberPositionDialog^ dialog = gcnew Dialogs::TSignalNumberPositionDialog();

  if(inputFormat)
     dialog->DataContext = oExchange_Text;
  else
     dialog->DataContext = oExchange_Value;

  dialog->ShowDialog();

重点是,覆盖的 selector 函数中的 item 值始终具有 null 值,我不知道如何在 XAML 中绑定它因为到目前为止我设法找到的所有示例都是 ListBoxes 等。没有关于如何基于视图模型显示不同控件的示例。

编辑:

按照建议,我在 ContentControl 中添加了 Content 属性 并向其传递了一个参数,该参数现在是 selector 中的 'item' 参数。工作正常!

您必须在 ContentControlContent 属性 中添加一些值。该值将作为 object item 传递给 SelectTemplate。您可能应该在您的 ViewModel 中绑定到它 属性 以便能够从那里更改它。

您不需要 DataTemplateSelector。 WPF提供了一种机制,可以根据Content的类型自动为ContentControl的ContentTemplate选择DataTemplate。

Data​Template.​Data​Type 中所述:

When you set this property to the data type without specifying an x:Key, the DataTemplate gets applied automatically to data objects of that type.

因此删除 x:Key 值和您的 DataTemplateSelector,设置 DataType

<dx:DXWindow.Resources>
    <DataTemplate DataType="{x:Type local:TInputValueVM}">
        <dxe:SpinEdit Height="23" MinWidth="200" Width="Auto"
                      Text="{Binding Path=Value, Mode=TwoWay}"
                      Mask="{Binding Mask, Mode=OneWay}" 
                      MaxLength="{Binding Path=InputLength}" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:TInputTextVM}">
        <dxe:TextEdit Height="23" MinWidth="200" Width="Auto"
                      Text="{Binding Path=Value, Mode=TwoWay}"
                      MaskType="RegEx" Mask="{Binding Mask, Mode=OneWay}"
                      MaxLength="{Binding Path=InputLength}"/>
    </DataTemplate>
</dx:DXWindow.Resources>

并将 ContentControl 的内容绑定到 属性,即 returns TInputValueVM 或 TInputTextVM:

<ContentControl Content="{Binding InputVM}" />

现在将自动选择合适的数据模板。