我有一个列表框,用于将前景颜色设置为红色的项目加载到其中。我想做的是:用鼠标选择一个项目后,将SelectedItem的前景色更改为黑色,但要使更改持久化,以便在取消选择该项目后,颜色保持黑色。顺便说一句,我想将其实现为向用户显示“已读项目”的方式。
基本上,我想要类似通用属性触发器的实现,如下面的代码,但取消选择后不恢复样式。我也玩过事件触发器,但运气不佳。
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="Foreground" Value="Black" /> //make this persist after deselection
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
提前感谢!
您可以为Foreground
属性设置动画:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(ListBoxItem.Foreground).(SolidColorBrush.Color)"
To="Black" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
这种简单方法的缺点是信息未存储在某处。这是纯可视化,没有任何数据支持。为了保留信息,以便重新启动应用程序显示相同的先前状态,您应该为数据模型引入专用属性,例如IsMarkedAsRead
。
根据您的要求,您可以覆盖ListBoxItem.Template
并将ToggleButton.IsChecked
绑定到IsMarkedAsRead
,或使用通过ICommand设置Button
属性的IsMarkedAsRead
。有很多解决方案,例如实现附加行为。
以下示例将覆盖ListBoxItem.Template
,将其变为Button
。现在,当单击该项目时,数据模型的IsMarkedAsRead
属性将设置为true
:
数据模型(有关Microsoft Docs: Patterns - WPF Apps With The Model-View-ViewModel Design Pattern的实现示例,请参见RelayCommand
。)
public class Notification : INotifyPropertyChanged
{
public string Text { get; set; }
public ICommand MarkAsReadCommand => new RelayCommand(() => this.IsMarkedAsRead = true);
public ICommand MarkAsUnreadCommand => new RelayCommand(() => this.IsMarkedAsRead = false);
private bool isMarkedAsRead;
public bool IsMarkedAsRead
{
get => this.isMarkedAsRead;
set
{
this.isMarkedAsRead = value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
ListBox
<ListBox ItemsSource="{Binding Notifications}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="{TemplateBinding Background}">
<Button x:Name="ContentPresenter"
ContentTemplate="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ItemTemplate}"
Content="{TemplateBinding Content}"
Command="{Binding MarkAsReadCommand}"
Foreground="Red">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsMarkedAsRead}" Value="True">
<Setter TargetName="ContentPresenter" Property="Foreground" Value="Green" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type Notification}">
<TextBlock Text="{Binding Text}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>