読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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