WPF - 如何将文本框添加到包含 ItemsControl 的项目的面板
WPF - How to add a textbox to the panel containing the Items of an ItemsControl
我的 ViewModel 具有 MultipleSelectionInfo 类型的属性,如下所示(为清楚起见,我删除了与 PropertyChanged 相关的代码,但我的绑定有效):
public abstract class MultipleSelectionInfo
{
// A SelectableObject is made of a bool IsSelected and a string ObjectData
public ObservableCollection<SelectableObject<string>> Items
{ get; set; }
public string Others
{ get; set; }
}
我这样显示这些属性:
我的 XAML 看起来像这样:
<DataTemplate x:Key="PrepControl">
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding ObjectData}" IsChecked="{Binding IsSelected}" Margin="0,6,8,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBox MaxWidth="400" MinWidth="100"
MaxHeight="20" Text="{Binding Others}" IsEnabled="{Binding IsOthersSelected}"
HorizontalAlignment="Left"/>
</WrapPanel>
</DataTemplate>
总而言之,我在 ItemsControl(水平 WrapPanel)中显示 MultipleSelectionInfo 的项目,然后显示 TextBox。最后,我将整个包裹在一个水平的 WrapPanel 中。
问题在于,由于 WrapPanel,TextBox 无法很好地与项目对齐。理想情况下,如果我可以在 ItemsControl 的 WrapPanel 中添加 TextBox,那将修复它。但我做不到。
可能吗?我应该怎么做?我很乐意避免以编程方式操纵 controls/panels 。如果我真的需要,我对 MVVM 不是很熟悉,你愿意解释一下吗?
以下是我期望达到的效果:
通用方法是创建一个 DataTemplateSelector
Typically, you create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object
在给定的情况下,我会尝试一个触发器,它修改 Others
项的 ContentTemplate:
<DataTemplate x:Key="PrepControl">
<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding ObjectData}"
IsChecked="{Binding IsSelected}"
Margin="0,6,8,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<Trigger Property="Content" Value="Others">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" VerticalAlignment="Center"/>
<TextBox Margin="5,0" VerticalAlignment="Center"
MinWidth="50"
IsEnabled="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}"
Text="{Binding Path=DataContext.Others, ElementName=Lst}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
通过 Trigger 选择 DataTemplate 的变体
<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst">
<ItemsControl.Resources>
<DataTemplate x:Key="CheckItem">
<CheckBox Content="{Binding ObjectData}"
IsChecked="{Binding IsSelected}"
Margin="0,6,8,0"/>
</DataTemplate>
<DataTemplate x:Key="OthersItem">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}"
Content="{Binding ObjectData}"
Margin="0,6,8,0"/>
<TextBox Margin="5,0" VerticalAlignment="Center"
MinWidth="50"
IsEnabled="{Binding IsSelected}"
IsHitTestVisible="True"
Text="{Binding Path=DataContext.Others, ElementName=Lst}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}">
<ContentPresenter.Style>
<Style TargetType="ContentPresenter">
<Setter Property="ContentTemplate" Value="{StaticResource CheckItem}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ObjectData}" Value="Others">
<Setter Property="ContentTemplate" Value="{StaticResource OthersItem}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我的 ViewModel 具有 MultipleSelectionInfo 类型的属性,如下所示(为清楚起见,我删除了与 PropertyChanged 相关的代码,但我的绑定有效):
public abstract class MultipleSelectionInfo
{
// A SelectableObject is made of a bool IsSelected and a string ObjectData
public ObservableCollection<SelectableObject<string>> Items
{ get; set; }
public string Others
{ get; set; }
}
我这样显示这些属性:
我的 XAML 看起来像这样:
<DataTemplate x:Key="PrepControl">
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding ObjectData}" IsChecked="{Binding IsSelected}" Margin="0,6,8,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBox MaxWidth="400" MinWidth="100"
MaxHeight="20" Text="{Binding Others}" IsEnabled="{Binding IsOthersSelected}"
HorizontalAlignment="Left"/>
</WrapPanel>
</DataTemplate>
总而言之,我在 ItemsControl(水平 WrapPanel)中显示 MultipleSelectionInfo 的项目,然后显示 TextBox。最后,我将整个包裹在一个水平的 WrapPanel 中。
问题在于,由于 WrapPanel,TextBox 无法很好地与项目对齐。理想情况下,如果我可以在 ItemsControl 的 WrapPanel 中添加 TextBox,那将修复它。但我做不到。
可能吗?我应该怎么做?我很乐意避免以编程方式操纵 controls/panels 。如果我真的需要,我对 MVVM 不是很熟悉,你愿意解释一下吗?
以下是我期望达到的效果:
通用方法是创建一个 DataTemplateSelector
Typically, you create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object
在给定的情况下,我会尝试一个触发器,它修改 Others
项的 ContentTemplate:
<DataTemplate x:Key="PrepControl">
<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding ObjectData}"
IsChecked="{Binding IsSelected}"
Margin="0,6,8,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<Trigger Property="Content" Value="Others">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" VerticalAlignment="Center"/>
<TextBox Margin="5,0" VerticalAlignment="Center"
MinWidth="50"
IsEnabled="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}"
Text="{Binding Path=DataContext.Others, ElementName=Lst}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
通过 Trigger 选择 DataTemplate 的变体
<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst">
<ItemsControl.Resources>
<DataTemplate x:Key="CheckItem">
<CheckBox Content="{Binding ObjectData}"
IsChecked="{Binding IsSelected}"
Margin="0,6,8,0"/>
</DataTemplate>
<DataTemplate x:Key="OthersItem">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}"
Content="{Binding ObjectData}"
Margin="0,6,8,0"/>
<TextBox Margin="5,0" VerticalAlignment="Center"
MinWidth="50"
IsEnabled="{Binding IsSelected}"
IsHitTestVisible="True"
Text="{Binding Path=DataContext.Others, ElementName=Lst}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}">
<ContentPresenter.Style>
<Style TargetType="ContentPresenter">
<Setter Property="ContentTemplate" Value="{StaticResource CheckItem}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ObjectData}" Value="Others">
<Setter Property="ContentTemplate" Value="{StaticResource OthersItem}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>