WPFのTreeViewでSelectedItemをバインドする

WPFのTreeViewにあるSelectedItemは何故かバインドできません。業務アプリが大好物のTreeViewのSelectedItemがバインドできないと画面で選択要素が変化したときになかなかめんどくさい実装をしないといけません。そこで、SelectedItemがバインド可能なカスタムTreeViewを作成しようと思います。

TreeViewを継承したBindableSelectedItemTreeViewの作成

TreeViewを継承してクラスを以下の通り宣言します。

/// <summary>
/// SelectedItem をバインド可能にする TreeView の拡張コントロールです。
/// </summary>
public class BindableSelectedItemTreeView : TreeView
{
    //
    // Bindable Definitions
    // - - - - - - - - - - - - - - - - - - - -

    public static readonly DependencyProperty BindableSelectedItemProperty
    #region...
        = DependencyProperty.Register(nameof(BindableSelectedItem), 
                typeof(object), typeof(BindableSelectedItemTreeView), new UIPropertyMetadata(null));
    #endregion

    //
    // Properties
    // - - - - - - - - - - - - - - - - - - - -

    /// <summary>
    /// Bind 可能な SelectedItem を表し、SelectedItem を設定または取得します。
    /// </summary>
    public object BindableSelectedItem
    {
        get { return (object)this.GetValue(BindableSelectedItemProperty); }
        set { this.SetValue(BindableSelectedItemProperty, value); }
    }

    //
    // Constructors
    // - - - - - - - - - - - - - - - - - - - -

    public BindableSelectedItemTreeView()
    {
        this.SelectedItemChanged += this.OnSelectedItemChanged;
    }

    //
    // Event Handlers
    // - - - - - - - - - - - - - - - - - - - -

    protected virtual void OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        if (this.SelectedItem == null)
        {
            return;
        }

        this.SetValue(BindableSelectedItemProperty, this.SelectedItem);
    }
}

そして利用側XAMLで以下の通りバインドします。

<Window x:Class="CustomTreeView"
        xmlns:custom="clr-namespace:CustomTreeView"> <!-- 追加 -->
        
    <Grid Margin="5">
        <custom:BindableSelectedItemTreeView 
            BindableSelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

これで、SelectedItemをバインドできました。