WinUI - データバインディング(Bindings->Update)

C++ で WinUI 3 ライブラリを使う

この記事は試行錯誤の結果をまとめたもので、WinUI の正しい使い方ではないかもしれません。

下図のようにTextBox に入力した文字列をもう一方のTextBoxに反映する方法を考えます。

XAMLはこんな感じです。入力用のTextBoxと出力用の読み取り専用のTextBoxがあります。

<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBox Header="String" />
    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE70D;" Margin="8"/>
    <TextBox  IsReadOnly="True" />
</StackPanel>

データバインディングで実現するためには、文字列の変数が1つあればよいので、.idl ファイルを開き、文字列型のValueStringプロパティを宣言します。

[default_interface]
runtimeclass Binding1Page : Microsoft.UI.Xaml.Controls.Page
{
    Binding1Page();
    String ValueString;
}

それと同時にクラスに ValueString のセッターとゲッターを実装します。

struct Binding1Page : Binding1PageT<Binding1Page>
{
    Binding1Page();

    void ValueString(const hstring& value) { m_valueString = value; }
    hstring ValueString() { return m_valueString; }

    private:
        hstring m_valueString;
};

次に ValueString とバインディングするようにXAMLファイルを修正します。

<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBox Header="String" Text="{x:Bind ValueString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE70D;" Margin="8"/>
    <TextBox Text="{x:Bind ValueString}" IsReadOnly="True" />
</StackPanel>

うまく動作しそうですが、ここまでのコードだと TextBox のテキストを変更する毎に ValueString のセッターは呼び出されていますが、出力用の TextBox は全然更新されません。

コードの値を画面に反映させるには、Bindings->Update(); を実行します。

ValueString のセッターの実装を値の変更があったときに Bindings->Update(); を実行するように変更すれば期待した動作になります。

void Binding1Page::ValueString(const hstring& value)
{
    if (m_valueString != value)
    {
        m_valueString = value;
        Bindings->Update();
    }
}

データバインディングを使わない方法

今回の例であればデータバインディングを使わない方が簡単かもしれません。

  1. コードから TextBox にアクセスできるように x:Name 属性で名前を付けます。
  2. テキストが変更されたときに呼び出される TextChanged イベントのイベントハンドラを入力用の TextBox に追加します。
  3. TextChanged イベントが発生したら、InputTextBox のテキストを OutputTextBox にコピーします。
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBox x:Name="InputTextBox" TextChanged="InputTextBox_TextChanged" Header="String" />
    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE70D;" Margin="8"/>
    <TextBox x:Name="OutputTextBox" IsReadOnly="True"/>
</StackPanel>
void winrt::NavigationView1::implementation::Binding1Page::InputTextBox_TextChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::Controls::TextChangedEventArgs const& e)
{
    OutputTextBox().Text(InputTextBox().Text());
}

参考

WinUI 3 with C++ 入門 - ビリヤードが好きなプログラマー

Microsoft インターフェイス定義言語 3.0 の概要 - Windows UWP applications | Microsoft Learn