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

残り僅かな全盛期

30代修行中の初心者プログラマー。いろいろなサイトを参考にコードを使用させてもらいます。

添付プロパティと添付ビヘイビア

添付プロパティについて調べてみた。

参考にしたサイトはこれ。
YKSoftware - for WPF Developers
非常に分かりやすかった。
ほぼそのままお借りしてコーディングしてみます。

まずは添付プロパティのクラス。

using System;
using System.Windows;
using System.Windows.Controls;

namespace AttachedPropertySample.AttachedProperty
{
    public class ButtonAtt
    {
        public static bool GetIsFileRefButton(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsFileRefButtonProperty);
        }

        public static void SetIsFileRefButton(DependencyObject obj, bool value)
        {
            obj.SetValue(IsFileRefButtonProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsFileRefButton.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsFileRefButtonProperty =
            DependencyProperty.RegisterAttached("IsFileRefButton", typeof(bool), typeof(ButtonAtt), new PropertyMetadata(false, OnIsFileRefChanged));

        private static void OnIsFileRefChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var b = d as Button;
            if(b != null)
            {
                if(GetIsFileRefButton(b))
                {
                    b.Click += OnClick;
                }
                else
                {
                    b.Click -= OnClick;
                }
            }
        }

        private static void OnClick(object sender, RoutedEventArgs e)
        {
            var b = sender as Button;
            if (b != null)
            {
                var dlg = new Microsoft.Win32.OpenFileDialog();
                var result = dlg.ShowDialog();

                if (result != null && result == true)
                {
                    var filename = dlg.FileName;

                    GetCallback(b)?.Invoke(filename);
                }
            }
        }


        //callback添付プロパティ
        public static Action<string> GetCallback(DependencyObject obj)
        {
            return (Action<string>)obj.GetValue(CallbackProperty);
        }

        public static void SetCallback(DependencyObject obj, Action<string> value)
        {
            obj.SetValue(CallbackProperty, value);
        }

        // Using a DependencyProperty as the backing store for Callback.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CallbackProperty =
            DependencyProperty.RegisterAttached("Callback", typeof(Action<string>), typeof(ButtonAtt), new PropertyMetadata(null));


        #endregion
    }
}

次に、View。

<Window x:Class="AttachedPropertySample.View.SubView"
        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:ignore="http://www.galasoft.ch/ignore"
        mc:Ignorable="d ignore"
        xmlns:att="clr-namespace:AttachedPropertySample.AttachedProperty"
        DataContext="{Binding Sub, Source={StaticResource Locator}}">

    <Grid>
        <StackPanel Orientation="Vertical">
            <Button x:Name="button1" Content="Button 1"/>
            <Button Content="Button 2" />
            <Button Content="Button 3" 
                    att:ButtonAtt.IsFileRefButton="True"
                    att:ButtonAtt.Callback="{Binding ReadFileCallback}"/>
            <TextBox Text="{Binding SubText}" />
        </StackPanel>
    </Grid>
</Window>

最後にViewModel。

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using AttachedPropertySample.View;
using System;
using System.Windows.Controls;

namespace AttachedPropertySample.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class SubViewModel : ViewModelBase
    {
        private string _subText;
        public string SubText
        {
            get
            {
                return _subText;
            }
            set
            {
                _subText = value;
                RaisePropertyChanged("SubText");
            }
        }

        /// <summary>
        /// Initializes a new instance of the SubWindowViewModel class.
        /// </summary>
        public SubViewModel()
        {
        }

        public Action<string> ReadFileCallback
        {
            get { return OnReadFile; }
        }

        private void OnReadFile(string obj)
        {
            SubText = obj;
        }
    }
}