我的顶级菜单中显示了错误通知列表。
<MenuItem Header="{Binding NotificationList.UnreadCount}"
HeaderStringFormat="Notifications ({0})"
ItemsSource="{Binding NotificationList.Notifications}">
</MenuItem>
我想做的是&#34;眨眼&#34;应用程序通过将背景颜色更改为红色然后每次NotificationList的大小更改(然后大于零)返回(ColorAnimation,1s,AutoRevert)。 NotificationList在更改时已经通知视图。
任何人都可以帮我编写正确的触发器来更改ItemsSource的大小,在此触发器中,更改应用程序窗口的背景颜色(不是元素本身)
答案 0 :(得分:1)
我不知道如何使用触发器执行此操作,但您可以创建一个attached behaviour,为ItemsSource的CollectionChanged事件添加处理程序。
前提是主窗口的背景设置为SolidColorBrush,如下所示
<Window ...>
<Window.Background>
<SolidColorBrush Color="{x:Static SystemColors.ControlColor}"/>
</Window.Background>
...
</Window>
这样的附加行为可能如下所示:
public class ItemsControlBehaviours
{
public static readonly DependencyProperty BlinkMainWindowOnItemsSourceChangeProperty =
DependencyProperty.RegisterAttached(
"BlinkMainWindowOnItemsSourceChange", typeof(bool), typeof(ItemsControlBehaviours),
new PropertyMetadata(BlinkMainWindowOnItemsSourceChangePropertyChanged));
public static bool GetBlinkMainWindowOnItemsSourceChange(ItemsControl itemsControl)
{
return (bool)itemsControl.GetValue(BlinkMainWindowOnItemsSourceChangeProperty);
}
public static void SetBlinkMainWindowOnItemsSourceChange(ItemsControl itemsControl, bool value)
{
itemsControl.SetValue(BlinkMainWindowOnItemsSourceChangeProperty, value);
}
private static void BlinkMainWindowOnItemsSourceChangePropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
ItemsControl itemsControl = obj as ItemsControl;
INotifyCollectionChanged collection;
if (itemsControl != null &&
(collection = itemsControl.ItemsSource as INotifyCollectionChanged) != null)
{
if ((bool)e.NewValue)
{
collection.CollectionChanged += ItemsSourceCollectionChanged;
}
else
{
collection.CollectionChanged -= ItemsSourceCollectionChanged;
}
}
}
private static void ItemsSourceCollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
{
SolidColorBrush background =
Application.Current.MainWindow.Background as SolidColorBrush;
if (background != null)
{
ColorAnimation backgroundAnimation = new ColorAnimation
{
To = Colors.Red,
Duration = TimeSpan.FromSeconds(1),
AutoReverse = true
};
background.BeginAnimation(
SolidColorBrush.ColorProperty, backgroundAnimation);
}
}
}
请注意,闪烁颜色和持续时间在这里是硬编码的,您可能需要找到一种参数化方法。
现在,您可以在任何设置了ItemsSource属性的ItemsControl上使用此行为:
<ListBox ItemsSource="..." Background="Transparent"
local:ItemsControlBehaviours.BlinkMainWindowOnItemsSourceChange="True" />
答案 1 :(得分:0)
这可能并不像你想的那么简单,但它可以满足你的需要。所有这些代码都在我的测试工具的主窗口中,所以有些东西可能需要根据您的具体情况进行更改。但这个想法是一样的。
我们需要做的第一件事就是让自己在集合发生变化时获得一个事件。我使用了一个可观察的集合,因为如果你有约束力,我会认为你正在使用它:
ObservableCollection<String> m_NotificationList;
// Propertized for binding purposes
public ObservableCollection<String> NotificationList
{
get
{
return m_NotificationList;
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
m_NotificationList = new ObservableCollection<string>() { "hey", "ho", "lets", "go" };
m_NotificationList.CollectionChanged += CollectionChangeCallback;
}
下一步是定义一些路由事件,我们可以在闪存时发送到窗口。我们在mainwindow的类定义中执行此操作,如上所述:
public static readonly RoutedEvent FlashEvent =
EventManager.RegisterRoutedEvent("Flash",
RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(MainWindow));
public event RoutedEventHandler Flash
{
add { AddHandler(FlashEvent, value); }
remove { RemoveHandler(FlashEvent, value); }
}
现在我们需要在集合更新时定义我们的回调,再次在mainwindow的类定义中:
void CollectionChangeCallback(object sender, EventArgs e)
{
// Don't fire if we don't want to flash
if (m_NotificationList.Count > 0)
window.RaiseEvent(new RoutedEventArgs(FlashEvent));
}
现在我们转到XAML并为我们的MainWindow添加一个触发器,它处理我们刚创建的路由事件并执行我们想要做的动画:
<Window.Triggers>
<EventTrigger RoutedEvent="local:MainWindow.Flash" >
<BeginStoryboard>
<Storyboard>
<ColorAnimation AutoReverse="True"
Duration="0:0:1"
FillBehavior="Stop"
From="White"
Storyboard.TargetName="window"
Storyboard.TargetProperty="Background.Color"
To="Red" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
这可以按照我在测试工具中的要求进行操作。这有点尴尬,但我找不到更好的方法来做到这一点。为清楚起见,我还将在此处包含我的XAML代码隐藏。它是一个带有MenuItem的空窗口和一个向集合添加字符串的按钮。你可以看到闪光灯以及事件聚集在一起的方式来实现它。
XAML:
<Window x:Class="WPFTestbed.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFTestbed"
x:Name="window"
Title="MainWindow"
Width="525"
Height="350">
<Window.Triggers>
<EventTrigger RoutedEvent="local:MainWindow.Flash" >
<BeginStoryboard>
<Storyboard>
<ColorAnimation AutoReverse="True"
Duration="0:0:1"
FillBehavior="Stop"
From="White"
Storyboard.TargetName="window"
Storyboard.TargetProperty="Background.Color"
To="Red" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<StackPanel>
<MenuItem x:Name="menu"
Header="{Binding NotificationList.Count}"
HeaderStringFormat="Notifications ({0})"
ItemsSource="{Binding NotificationList}">
</MenuItem>
<Button Click="Button_Click"
Content="Hi" />
</StackPanel>
</Window>
背后的代码( - 包括空格):
namespace WPFTestbed
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public static readonly RoutedEvent FlashEvent =
EventManager.RegisterRoutedEvent("Flash",
RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(MainWindow));
public event RoutedEventHandler Flash
{
add { AddHandler(FlashEvent, value); }
remove { RemoveHandler(FlashEvent, value); }
}
ObservableCollection<String> m_NotificationList;
public ObservableCollection<String> NotificationList
{
get
{
return m_NotificationList;
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
m_NotificationList = new ObservableCollection<string>() { "hey", "ho", "lets", "go" };
m_NotificationList.CollectionChanged += CollectionChangeCallback;
}
void CollectionChangeCallback(object sender, EventArgs e)
{
if (m_NotificationList.Count > 0)
window.RaiseEvent(new RoutedEventArgs(FlashEvent));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
m_NotificationList.Add("Another");
}
}
}