[WPF] Binding を強制的に更新反映する [C#]

[WPF] Binding を強制的に更新反映する [C#]

WPF バインドしている値を強制的に反映したい

WPF ではビューに値をバインドできます。

バインドしている値の変更通知を行うとビューにその値が反映されますし、ビューの入力値が更新されれば何かしらのタイミングでバインドしている値が更新されます。

ただ場合によっては任意のタイミングで明示的に、強制的にコード上からバインドを更新したい場合があります。そのような場合にはバインド評価更新用のメソッドを実行することで実現可能です。

GetBindingExpression でバインディングを更新する

BindingOperations.GetBindingExpression() は指定されたオブジェクトからバインディング対象のプロパティに関連付いた評価式を取得します。これで取得できる評価式を実行することで任意のタイミングでバインディングを更新できます。

例えばテキストボックスとテキストブロックだけの画面を用意します。両方にテキストがバインドされているような画面です。それからボタンを2つ用意します。

<TextBox x:Name="MyTextBox" Text="{Binding Text}"></TextBox>
<TextBlock x:Name="MyTextBlock" Text="{Binding Text}"></TextBlock>
<Button Click="Button_Click">更新(UpdateTarget)</Button>
<Button Click="Button_Click_1">更新(UpdateSource)</Button>

コードビハインドはこんな感じです。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        // VM(Source) -> テキストボックス(Target)
        var vm = this.DataContext as ViewModel;
        vm.Text = DateTime.Now.ToString();

        var bindingExpression = BindingOperations.GetBindingExpression(this.MyTextBox, TextBox.TextProperty);
        bindingExpression.UpdateTarget();
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        // テキストボックス(Target) -> VM(Source)
        MyTextBox.Text = DateTime.Now.ToString();

        var bindingExpression = BindingOperations.GetBindingExpression(this.MyTextBox, TextBox.TextProperty);
        bindingExpression.UpdateSource();

        // VMに反映されているか確認
        MessageBox.Show((this.DataContext as ViewModel).Text);
    }
}

class ViewModel
{
    public string Text { get; set; }
}

VM(Source) から テキストボックス(Target) に強制反映

まず BindingOperations.GetBindingExpression() でバインドされているビューモデルの値を、強制的にビューに反映する方法です。

引数には対象となるコントロールとそのプロパティを指定します。取得した式の UpdateTarget を指定すると指定したコントロールのプロパティがバインド値で更新されます。

// VM(Source) -> テキストボックス(Target)
var vm = this.DataContext as ViewModel;
vm.Text = DateTime.Now.ToString();

// テキストボックスのTextプロパティのバインディングを更新評価する
var bindingExpression = BindingOperations.GetBindingExpression(this.MyTextBox, TextBox.TextProperty);
bindingExpression.UpdateTarget();

この例では現在日時をビューモデルに設定した後、その値をテキストボックスに反映させています。具体的にはテキストボックスのテキストプロパティに紐づくバインドの更新式を取得し、UpdateTarget() でバインドされた値をテキストボックスに反映しています。

実行例はこんな感じ。

現在日時がビューモデルからビューに反映されていることが分かります。あくまでテキストボックスのテキストプロパティに対して更新しているのみなのでテキストブロックのほうには反映されません。

VM(Source) から テキストボックス(Target) に強制反映

UpdateSource() を実行すると対象ビューのプロパティに紐づくビューモデルの値に対して強制的に反映させられます。

例えばテキストボックスのテキストプロパティを更新して、それをビューモデルにコード上で反映させる例です。

// テキストボックス(Target) -> VM(Source)
MyTextBox.Text = DateTime.Now.ToString();

// テキストブロックのテキストプロパティのバインドを更新する
var bindingExpression = BindingOperations.GetBindingExpression(this.MyTextBox, TextBox.TextProperty);
bindingExpression.UpdateSource();

// VMに反映されているか確認
MessageBox.Show((this.DataContext as ViewModel).Text);

実行例はこんな感じ。

テキストボックスに紐づくプロパティに強制的に値を反映しています。テキストブロックにも反映されました。

マルチバインディングの場合

複数の値をバインドするマルチバインディングの場合、BindingOperations.GetBindingExpression() はうまく働きません。BindingOperations.GetMultiBindingExpression() を使用します。

試してないで詳細は不明ですがたぶん。

以上。

参考URL

.NET Frameworkカテゴリの最新記事