0

トップメニューにエラー通知のリストが表示されています。

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

私がやりたいのは、NotificationListのサイズが変更されるたびに(そしてゼロより大きい)、背景色を赤に変更してから元に戻す(ColorAnimation、1s、AutoRevert)ことによって、アプリケーションを「点滅」させることです。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 に答える