在 ItemsControl 中添加不同的控件
Add different controls in ItemsControl
我需要根据特定条件在 ItemsControl 中添加不同的控件(TextBox/CheckBox/ComboBox,等等)。
ItemsControl 中的每个 Item 都是一个名称-值对。名称始终由 TextBlock 表示,但值可以是任何 UI 控件。
我使用水平对齐的 StackPanel 来表示每个项目。 StackPanel 中的第一个控件仍然是 TextBlock,但第二个控件依赖于运行时在 ViewModel 中设置的 "ItemDataType" 属性。
我遇到的问题是我无法使用带 ItemDataType 的 Style 触发器在 StackPanel 的第二个元素中分配不同的控件 属性。
代码片段:
<UserControl.Resources>
<DataTemplate x:Key="TextBoxTemplate">
<TextBox Text="{Binding Path=DataValue}"/>
</DataTemplate>
<DataTemplate x:Key="ComboBoxTemplate">
<ComboBox ItemsSource="{Binding Path=SelectionList}" SelectedValue="{Binding Path=DataValue,Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<CheckBox IsChecked="{Binding Path=DataValue,Mode=TwoWay}" />
</DataTemplate>
<DataTemplate x:Key="ButtonTemplate">
<Button Content="{Binding Path=DataValue}"/>
</DataTemplate>
<DataTemplate x:Key="dynamicTemplate">
<StackPanel Orientation="Horizontal" Tag="{Binding ItemDataType}">
<TextBlock Text="{Binding Path=DataName,Mode=TwoWay}"/>
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ItemDataType}" Value="TextBox">
<Setter Property="Template" Value="{StaticResource TextBoxTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<!-- CONTROL LAYOUT -->
<ItemsControl ItemsSource="{Binding Path=DataList,Mode=TwoWay}" ItemTemplate="{StaticResource dynamicTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
我得到的错误是 DataTemplate 对 ContentControl.Template 属性 无效。我明白我的做法是错误的,但我需要帮助以正确的方式做事。
谢谢,
RDV
我想要一个 XAML 解决方案 - 花了我一些时间:-)。
以下是工作代码:
<Style x:Key="nvpTextBlockStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Width" Value="{Binding Path=LabelWidthStr, FallbackValue=50}"/>
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="Text" Value="{Binding Path=NameData,Mode=TwoWay}"/>
<Setter Property="FontSize" Value="16"/>
</Style>
<DataTemplate x:Key="textBoxTemplate">
<TextBox Margin="1,1" Text="{Binding Path=ValueData,UpdateSourceTrigger=PropertyChanged,
ValidatesOnExceptions=True,NotifyOnValidationError=True,ValidatesOnDataErrors=True}"/>
</DataTemplate>
<DataTemplate x:Key="comboBoxTemplate">
<ComboBox HorizontalAlignment="Left" ItemsSource="{Binding Path=SelectionList}"
SelectedValue="{Binding Path=ValueData,Mode=TwoWay}"
IsEnabled="{Binding IsDataItemEnabled}"/>
</DataTemplate>
<DataTemplate x:Key="checkBoxTemplate">
<CheckBox HorizontalAlignment="Left" VerticalAlignment="Center"
IsChecked="{Binding Path=ValueData,Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="buttonTemplate">
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.AddCommand}"
CommandParameter="{Binding}" Width="30" Height="25">
<TextBlock Text="🔑" FontFamily="Segoe UI Symbol" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" />
</Button>
</DataTemplate>
<DataTemplate x:Key="dynamicTemplate">
<StackPanel Orientation="Horizontal" Margin ="5">
<TextBlock Style="{StaticResource nvpTextBlockStyle}"/>
<ContentPresenter Content="{Binding}"
Tag="{Binding Path=CustomDataType, FallbackValue={x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}}">
<ContentPresenter.Resources>
<Style TargetType="{x:Type ContentPresenter}">
<Style.Triggers>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource textBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.COMBOBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource comboBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.CHECKBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource checkBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.BUTTON_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource buttonTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</StackPanel>
</DataTemplate>
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Path=CustomDataList,Mode=TwoWay}"
ItemTemplate="{StaticResource dynamicTemplate}";
KeyboardNavigation.IsTabStop="False">
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
谢谢,
RDV
我需要根据特定条件在 ItemsControl 中添加不同的控件(TextBox/CheckBox/ComboBox,等等)。 ItemsControl 中的每个 Item 都是一个名称-值对。名称始终由 TextBlock 表示,但值可以是任何 UI 控件。 我使用水平对齐的 StackPanel 来表示每个项目。 StackPanel 中的第一个控件仍然是 TextBlock,但第二个控件依赖于运行时在 ViewModel 中设置的 "ItemDataType" 属性。
我遇到的问题是我无法使用带 ItemDataType 的 Style 触发器在 StackPanel 的第二个元素中分配不同的控件 属性。
代码片段:
<UserControl.Resources>
<DataTemplate x:Key="TextBoxTemplate">
<TextBox Text="{Binding Path=DataValue}"/>
</DataTemplate>
<DataTemplate x:Key="ComboBoxTemplate">
<ComboBox ItemsSource="{Binding Path=SelectionList}" SelectedValue="{Binding Path=DataValue,Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<CheckBox IsChecked="{Binding Path=DataValue,Mode=TwoWay}" />
</DataTemplate>
<DataTemplate x:Key="ButtonTemplate">
<Button Content="{Binding Path=DataValue}"/>
</DataTemplate>
<DataTemplate x:Key="dynamicTemplate">
<StackPanel Orientation="Horizontal" Tag="{Binding ItemDataType}">
<TextBlock Text="{Binding Path=DataName,Mode=TwoWay}"/>
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding ItemDataType}" Value="TextBox">
<Setter Property="Template" Value="{StaticResource TextBoxTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid>
<!-- CONTROL LAYOUT -->
<ItemsControl ItemsSource="{Binding Path=DataList,Mode=TwoWay}" ItemTemplate="{StaticResource dynamicTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
我得到的错误是 DataTemplate 对 ContentControl.Template 属性 无效。我明白我的做法是错误的,但我需要帮助以正确的方式做事。
谢谢,
RDV
我想要一个 XAML 解决方案 - 花了我一些时间:-)。 以下是工作代码:
<Style x:Key="nvpTextBlockStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Width" Value="{Binding Path=LabelWidthStr, FallbackValue=50}"/>
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="Text" Value="{Binding Path=NameData,Mode=TwoWay}"/>
<Setter Property="FontSize" Value="16"/>
</Style>
<DataTemplate x:Key="textBoxTemplate">
<TextBox Margin="1,1" Text="{Binding Path=ValueData,UpdateSourceTrigger=PropertyChanged,
ValidatesOnExceptions=True,NotifyOnValidationError=True,ValidatesOnDataErrors=True}"/>
</DataTemplate>
<DataTemplate x:Key="comboBoxTemplate">
<ComboBox HorizontalAlignment="Left" ItemsSource="{Binding Path=SelectionList}"
SelectedValue="{Binding Path=ValueData,Mode=TwoWay}"
IsEnabled="{Binding IsDataItemEnabled}"/>
</DataTemplate>
<DataTemplate x:Key="checkBoxTemplate">
<CheckBox HorizontalAlignment="Left" VerticalAlignment="Center"
IsChecked="{Binding Path=ValueData,Mode=TwoWay}"/>
</DataTemplate>
<DataTemplate x:Key="buttonTemplate">
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.AddCommand}"
CommandParameter="{Binding}" Width="30" Height="25">
<TextBlock Text="🔑" FontFamily="Segoe UI Symbol" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" />
</Button>
</DataTemplate>
<DataTemplate x:Key="dynamicTemplate">
<StackPanel Orientation="Horizontal" Margin ="5">
<TextBlock Style="{StaticResource nvpTextBlockStyle}"/>
<ContentPresenter Content="{Binding}"
Tag="{Binding Path=CustomDataType, FallbackValue={x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}}">
<ContentPresenter.Resources>
<Style TargetType="{x:Type ContentPresenter}">
<Style.Triggers>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource textBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.COMBOBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource comboBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.CHECKBOX_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource checkBoxTemplate}"/>
</Trigger>
<Trigger Property="Tag" Value="{x:Static local:CustomViewModel.BUTTON_TEMPLATE}">
<Setter Property="ContentTemplate" Value="{StaticResource buttonTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</StackPanel>
</DataTemplate>
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Path=CustomDataList,Mode=TwoWay}"
ItemTemplate="{StaticResource dynamicTemplate}";
KeyboardNavigation.IsTabStop="False">
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
谢谢,
RDV