より良いエンジニアを目指して

1日1つ。良くなる!上手くなる!

WPFのUserControlに対してBindingする

初歩的なことなのにど忘れしていたのがUserControlに対してBindingする方法。

例えば以下のようなUserControlがあったとします

        <Button Content="OK" Width="75" Margin="15 8 15 8" x:Name="ButtonOk"/>

このButtonOkの Commandに対して親WindowからBindingしたい場合。

xaml.csでDependencyPropertyは以下のように追加

        public static readonly DependencyProperty OkCommandProperty = DependencyProperty.Register(nameof(OkCommand), typeof(ICommand), typeof(OkPanel));

        public ICommand OkCommand
        {
            get => (ICommand) GetValue(OkCommandProperty);
            set => SetValue(OkCommandProperty, value);
        }

xamlはこのようにして

    <Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:OkPanel}}}">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
        <Button Content="OK" Width="75" Margin="15 8 15 8" x:Name="ButtonOk" Command="{Binding OkCommand}"/>
    </StackPanel>
    </Grid>

あとは親Windowから以下のように追加

        <controls:OkPanel OkCommand="{Binding OkCommand}"/>

こういうのがパッと出ず、Webを彷徨ってしまうのは私のコードを書く量の少なさに問題があります。(最近気づいた)

もう一つ理由を挙げるとDependencyPropertyのとっつきづらさでしょう。

staticメンバとクラスプロパティの組み合わせでDependencyProperyを用意しますし、DependencyPropertyの宣言はとてつもなく複雑で敬遠してしまいがちです。

もう少しわかりやすいアーキテクチャであって欲しかったですし、WPFの敷居の高さを上げることに繋がっているかなとも感じます。

とはいえ、DependencyPropertyの宣言もnameofや=>などの言語仕様によって大分、かっちり書けるようになっています。

あとは、人がついていけるか。コードを書いて慣れながら理解を深めていくしかないでしょうね。

docs.microsoft.com

参考記事

stackoverflow.com

araramistudio.jimdo.com

NGケース

UserControlにCommand={Binding OkCommand} などと追加してしまうと、OkCommandを親Windowで指定していないと、Binding Errorが起きてしまって柔軟性に欠けます。

で、私はプログラムでBindingすればいい! とこんなことをしてました。

            var okBinding = new Binding(nameof(viewModel.OkCommand))
            {
                Source = viewModel
            };
            OkPanel.ButtonOk.SetBinding(Button.CommandProperty, okBinding);