0

我的顶部菜单中显示了错误通知列表。

<MenuItem Header="{Binding NotificationList.UnreadCount}"
    HeaderStringFormat="Notifications ({0})"
    ItemsSource="{Binding NotificationList.Notifications}">
 </MenuItem>

我想做的是通过将背景颜色更改为红色然后返回(ColorAnimation,1s,AutoRevert)来“闪烁”应用程序,每次 NotificationList 的大小发生变化(并且大于零)。NotificationList 已在视图更改时通知视图。

任何人都可以帮助我编写正确的触发器以更改 ItemsSource 的大小并在此触发器内更改应用程序窗口的背景颜色(而不是元素本身)

4

2 回答 2

1

我不知道如何使用触发器执行此操作,但您可以创建一个附加行为,将处理程序添加到 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" />
于 2012-08-15T14:51:04.827 回答
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;
  }

下一步是定义一些路由事件,我们可以在需要闪烁时将其发送到窗口。我们在主窗口的类定义中这样做,如上:

     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); }
  }

现在我们需要在集合更新时定义回调,再次在主窗口的类定义中:

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");
      }
   }
}
于 2012-08-15T16:13:52.943 回答