问题
I want to create a simple window that would display different controls (SpinEdit
or TextEdit
) based on the view-model that is selected.
I have the code and logic behind it done already, what is left is displaying the control (SpinEdit
or TextEdit
) itself.
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>
Where in the <ContentControl>
I want to select which control will be displayed (SpinEdit
for numbers and TextEdit
for 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;
}
}
Where I want to return a specific DataTemplate
based on the view-model that is created in the c++/cli code.
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();
The point is, the item
value in the overriden selector function always has the null
value and I have no idea how to bind it in XAML since all the examples I've managed to find so far are ListBox
es etc. There's no example on how to display different controls based on the view-model.
EDIT:
As suggested, I added Content property in the ContentControl and passed it an argument which is now the 'item' argument in the selector. Works just fine!
回答1:
You do not need a DataTemplateSelector. WPF provides a mechanism that automatically selects a DataTemplate for the ContentTemplate of a ContentControl according to the type of a Content.
As explained in DataTemplate.DataType:
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.
So drop the x:Key
value and your DataTemplateSelector, set 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>
and bind the ContentControl's Content to a property that returns either a TInputValueVM or a TInputTextVM:
<ContentControl Content="{Binding InputVM}" />
The appropriate DataTemplate will now be selected automatically.
回答2:
You have to add some value in the Content
property of the ContentControl
. That value will be passed to the SelectTemplate
as the object item
. You probably should bind to it some property in your ViewModel to be able to change that from there.
来源:https://stackoverflow.com/questions/53226179/how-to-use-datatemplateselector-with-contentcontrol-to-display-different-control