【C# WPF】BindingでTextBoxの入力をTextBlockに反映させる

Wpf Sheep Calender 3日目。

テキストボックスにデータバインディングを設定する事で、その入力内容をテキストブロックにリアルタイムに反映させます。

面倒なのでChatGPTでやらせました。
自力でやると大体上手くいかないからです(笑)
思ってたよりだいぶ単純な実装です。

高度な事は書いてないですがいいねされると嬉しいかも知れないなと


# サンプルコード

```xml:MainWindow.xaml


<Window x:Class="TextToLabel_ReflentionBinding.MainWindow"
        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:local="clr-namespace:TextToLabel_ReflentionBinding"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel Margin="20">
          <!--テキストボックスとテキストブロック双方向でBindする-->
            <TextBox Text="{Binding TextBoxContent, UpdateSourceTrigger=PropertyChanged}" Height="25"/>
            <TextBlock Text="{Binding TextBoxContent}" Margin="0,10,0,0"/>
        </StackPanel>
    </Grid>
</Window>

```

コメントはChatGPTに書いて貰いました。

```csharp:MainViewModel.cs
using System.ComponentModel;

namespace TextToLabel_ReflentionBinding
{
    // MainViewModel クラスの定義。INotifyPropertyChanged インターフェイスを実装して、
    // プロパティ値の変更をビューに通知する機能を提供します。
    public class MainViewModel : INotifyPropertyChanged
    {
        private string _textBoxContent = string.Empty;

       
        public string TextBoxContent
        {
            get => _textBoxContent;
            set
            {
                if (_textBoxContent != value)
                {
                    _textBoxContent = value;
                    // 値が変更されるとプロパティ変更通知が発行される。
                    //公開プロパティに対して
                    //イベントを発火させるのでvalueはダメ
                    OnPropertyChanged(nameof(TextBoxContent));
                }
            }
        }

        // PropertyChanged イベントの定義。
        // INotifyPropertyChanged インターフェイスを通じて宣言されます。
        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            // プロパティが空またはnullの場合は例外を投げる。
            if (string.IsNullOrEmpty(propertyName)) throw new InvalidOperationException("PropertyChanged event is not subscribed.");
            
            //イベントを発行 PropertyChanged?でNull Checkにもなる
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}


```

コードビハインドには何も書かなくていいです。


# 実行結果
![bandicam 2024-04-13 20-34-04-553_Harua.mp4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/fc4f0225-fd17-5571-ec49-d7607dc67df1.gif)


プロパティが変更されたときのみイベントを発生させます。そのため、TextChangedを使うよりもパフォーマンスが良好です。



補足

:::note warn
```csharp
DataContext = this;
```
と共存出来ません。上書きされます。
:::


# MainWindowのDataContextと共存させるには？

**不可能です**
コントロール個別にBindingを設定する必要があります。コードビハインド側で書きます。


## 外観

```csharp
 <ComboBox x:Name="VideoCodecBox"                                      
           SelectedIndex="0"
     Width="150" Margin="20,0,0,0"/>
 <ComboBox x:Name="AudioCodecBox" Width="150" Margin="6"          
             SelectedIndex="0"/>
```

## Code例
※今開発中の実装なのでこのままでは動きません
XAML側の``UpdateSourceTrigger.PropertyChanged`` 等は削除しないと動きません

```csharp

     private void Window_Loaded(object sender, RoutedEventArgs e)
     {
      //DataContext = this; だとインスタンスが上書きされてしまい、動作しない

       //個別にBindingを設定する
         Binding VideoCodecBinding = new Binding(nameof(FfmpegVideoCodecDic))
         {
             Source = this,

             Mode = BindingMode.OneWay
         };

         VideoCodecBox.SetBinding(ItemsControl.ItemsSourceProperty, VideoCodecBinding);
         VideoCodecBox.DisplayMemberPath = "Key";  // 辞書のキーを表示する
         VideoCodecBox.SelectedValuePath = "Value";


         Binding audioCodecBinding = new Binding(nameof(FfmpegAudioCodecDic))
         {
             Source = this,

             Mode = BindingMode.OneWay
         };

         AudioCodecBox.SetBinding(ItemsControl.ItemsSourceProperty, audioCodecBinding);
         AudioCodecBox.DisplayMemberPath = "Key";  // 辞書のキーを表示する
         AudioCodecBox.SelectedValuePath = "Value";


         TextBox textDisp = queryUpDown1.FindName("NUDTextBox") as TextBox;
        textDisp.Text = "500";
         
         // QueryBuildUpDownにバインディングの設定
         Binding binding = new Binding(nameof(qf.BuildQueryes))
         {     
             UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
             Mode = BindingMode.TwoWay
         };


         //表示用のテキストブロックにバインド
         textDisp.SetBinding(TextBox.TextProperty, binding);
         
     }
 ```

## 結果
あくまで見本って事で
![bandicam 2024-04-14 00-46-29-471_Harua.mp4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/72d1a385-1211-8808-35a1-7d74c8006ec9.gif)