かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

WPFのBehaviorをStyleで使う方法

昔書いた記事にコメントがついたので改めてやってみました。

blog.okazuki.jp

最近はGitHubがあるのでコードを共有するのが楽でいいですね。

こんなクラスを用意してやります。BehaviorをCloneして追加してやる感じです。Cloneして渡さないと同じBehaviorのインスタンスは、複数クラスにアタッチできないのがポイントです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interactivity;

namespace StyleBehaviorSampleApp
{
    public class StyleBehaviorCollection : FreezableCollection<Behavior>
    {

        public static readonly DependencyProperty StyleBehaviorsProperty =
            DependencyProperty.RegisterAttached(
                "StyleBehaviors", 
                typeof(StyleBehaviorCollection), 
                typeof(StyleBehaviorCollection), 
                new PropertyMetadata((sender, e) =>
                {
                    if (e.OldValue == e.NewValue) { return; }

                    var value = e.NewValue as StyleBehaviorCollection;
                    if (value == null) { return; }

                    var behaviors = Interaction.GetBehaviors(sender);
                    behaviors.Clear();
                    foreach (var b in value.Select(x => (Behavior)x.Clone()))
                    {
                        behaviors.Add(b);
                    }
                }));

        public static StyleBehaviorCollection GetStyleBehaviors(DependencyObject obj)
        {
            return (StyleBehaviorCollection)obj.GetValue(StyleBehaviorsProperty);
        }

        public static void SetStyleBehaviors(DependencyObject obj, StyleBehaviorCollection value)
        {
            obj.SetValue(StyleBehaviorsProperty, value);
        }

        protected override Freezable CreateInstanceCore()
        {
            return new StyleBehaviorCollection();
        }
    }
}

あとは、適当なBehaviorを作ってこんな感じで使います。

<Window x:Class="StyleBehaviorSampleApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:StyleBehaviorSampleApp"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Window.Resources>
        <Style x:Key="ButtonAlertStyle"
               TargetType="{x:Type Button}">
            <Setter Property="local:StyleBehaviorCollection.StyleBehaviors">
                <Setter.Value>
                    <local:StyleBehaviorCollection>
                        <local:AlertBehavior Message="Hello world" />
                    </local:StyleBehaviorCollection>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <StackPanel>
        <Button Content="Alert1"
                Style="{StaticResource ButtonAlertStyle}" />
        <Button Content="Alert2"
                Style="{StaticResource ButtonAlertStyle}" />
        <Button Content="Alert3"
                Style="{StaticResource ButtonAlertStyle}" />
    </StackPanel>
</Window>

ソースコード全体は以下からどうぞ。

github.com