我想显示一个ListBox,其选中的项目将显示一个按钮,该按钮对所选数据项执行特定操作。为此,我使用两个DataTemplates,一个是 NormalTemplate (没有按钮),另一个是 SelectedTemplate (它有一个按钮,其Tag属性绑定到数据,这是用于按钮单击事件处理程序)。当选择列表框中的项目时,我想分配SelectedTemplate。
为此,我使用自定义ControlTemplate,它具有VisualStateManager,它根据VisualState选择适当的模板(即,Selected和ampselected)。这个解决方案的问题是我每次需要使用不同的DataTemplates时都要创建新的ControlTemplate。我正在尝试找到一个解决方案,您可以在其中指定普通模板和模板。选择项目并使用通用代码根据visualstate更改datatemplate。
以下是我的DataTemplate for Unselected&选定项目:
<DataTemplate x:Key="NormalItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Margin="8,0,0,3" VerticalAlignment="Center">
<TextBlock Text="{Binding Name}" FontWeight="Bold" FontFamily="Arial" FontSize="14"/>
<TextBlock Text="{Binding Description}" />
</StackPanel>
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Key="SelectedItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="65"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Margin="8,0,0,3">
<TextBlock Text="{Binding Name}" FontWeight="Bold" FontFamily="Arial" FontSize="14"/>
<TextBlock Text="{Binding Description}" />
</StackPanel>
<Border Grid.Column="2" Grid.RowSpan="2" VerticalAlignment="Stretch">
<Button Content="Process" Tag={Binding} OnClick="Process_Clicked" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</Grid>
</Border>
</DataTemplate>
下面是定义自定义ControlTemplate的样式,它使用VisualStateManager来显示或隐藏其ContentTemplate被分配给NormalItemTemplate&amp;的适当ContentPresenters。 SelectedItemTemplate
<Style TargetType="ListBoxItem" x:Key="ActiveGamesItemContainerStyle">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectedContentPresenter" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="UnSelectedContentPresenter" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectedContentPresenter" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="UnSelectedContentPresenter" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter
x:Name="SelectedContentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{StaticResource NormalItemTemplate}"
HorizontalAlignment="Stretch"
Margin="{TemplateBinding Padding}"
Visibility="Collapsed"/>
<ContentPresenter
x:Name="UnSelectedContentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{StaticResource SelectedItemTemplate}"
HorizontalAlignment="Stretch"
Margin="{TemplateBinding Padding}"
Visibility="Visible"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
此解决方案的问题是:
对于需要使用不同DataTemplates的每个新ListBoxItem,我需要使用ControlTemplate创建一个与上面相同的样式,但只需要更改ContentPresenter的ContentTemplate。因此,很多重复的代码/ XAML。
因为我正在使用SelectedItemTemplate中的按钮,所以我需要在同一个UserControl类中定义样式,其中定义了Click事件处理程序。如果UserControl使用多个ListBox,则会为每个ListBox声明一个巨大的Style定义。
我尝试使用附加属性解决此问题,但它无法正常工作。因为,我无法获得Selected ListBoxItem(相反,我得到了绑定数据)。我们的想法是获取ListBoxItem获取其ContentPresenter并将其ContentTemplate设置为SelectedItemTemplate。
有没有更好的方法呢?
谢谢&amp;问候, 苏尼
答案 0 :(得分:1)
无需使用两个单独的模板,只需使用一个模板并使用DataTrigger
切换可见性。
创建具有IsSelected
属性的项目的视图模型。添加NotifyPropertyChanged事件。
设置ItemContainerStyle
以将ListBoxItem.IsSelected
属性绑定到您的viewmodel上的IsSelected
属性。
然后在DataTemplate
中DataTrigger
Visibility
,IsSelected
True
{{1}}时会更改{{1}}。
有关如何执行上述操作的示例,请查看answer to this StackOverflow question.