123 田宮k8 カジノWPF:ラジオボタンの選択をバインディングソースに反映させるには?[C#/VB]仮想通貨カジノパチンコうる星 やつ ら 199

123 田宮k8 カジノWPF:ラジオボタンの選択をバインディングソースに反映させるには?[C#/VB]仮想通貨カジノパチンコうる星 やつ ら 199

パズル ゲーム 人気 アプリk8 カジノ .NET TIPSInsider.NET

町田 パチンコ 2 ちゃんねる 

「.NET TIPS」のインデックス

連載目次

対象:.NET 3.5以降

 UIコントロールの状態の変化をデータに反映させたい場合がある。そんなとき、XAMLでは双方向のデータバインディングを利用するのが便利だ。例えば、エンドユーザーがテキストボックスに入力した文字列は、データバインディングによってバインディングソースの文字列型プロパティに自動的に反映させられる。あるいは、スライダーの「つまみ」の位置を浮動小数点数のプロパティに反映できる。では、ラジオボタンの選択状態を列挙型や整数型のプロパティに反映できないだろうか? その主な方法には2通りあるのだが、本稿では簡単な方を解説する。

 なお、本稿のサンプルは「Windows desktop code samples:.NET Tips #1126」からダウンロードできる*1。

*1 本稿の内容はUWPアプリにも適用できる。ただし、後述するようにデータの変更をラジオボタンに反映できないという欠点がある。UWPアプリでは、データバインディングにコンバータを介する方法を使うべきである。そのため、UWPアプリについては本稿でも扱わないし、サンプルコードにも含めていない。

ラジオボタンの選択をデータに反映させる2通りの方法

 RadioButtonコントロール(System.Windows.Controls名前空間)の選択状態は、真偽値型のIsCheckedプロパティで示される。例えば、三つの選択肢に対応した三つのラジオボタンがあるとする。しかしそこには「三つの選択肢のどれが選択されているか」を表すプロパティは存在しない。あるのは、三つのIsCheckedプロパティだけなのだ。三つの状態を取り得る列挙型のデータとバインドしたくても、直接バインドすることはできない。

 そこで考えられる解決策の一つは、三つの選択肢に対応した三つ真偽値型プロパティをデータの側にも用意する方法だ。考え方は簡単ではあるが、データの変更をラジオボタンに反映させる方法に難があるという弱点がある。本稿では、この方法を解説する。

 もう一つは、.NET 4以降に限定されるが、データバインディングにコンバータを介する方法だ。こちらは別稿に譲りたい。

例題

 例として、次のコードのようなデータを考えてみよう。三つの状態を取れる列挙型のプロパティを持っているクラスだ。

public enum SampleEnum{ Undefined, One = 1, Two, Three,}public class SampleData : System.ComponentModel.INotifyPropertyChanged{ private SampleEnum _value; // One,Two,Three public SampleEnum Value { get { return _value; } set { if (_value == value) return; if (!Enum.IsDefined(typeof(SampleEnum),value)) throw new ArgumentOutOfRangeException(); var handler = PropertyChanged; _value = value; if (handler != null) { handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Value")); } } } #region INotifyPropertyChanged メンバー public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; #endregion}

Public Enum SampleEnum Undefined One = 1 Two ThreeEnd EnumPublic Class SampleData Implements System.ComponentModel.INotifyPropertyChanged Private _value As SampleEnum ' One,Two,Three Public Property Value As SampleEnum Get Return _value End Get Set(value As SampleEnum) If (_value = value) Then Return End If If (Not [Enum].IsDefined(GetType(SampleEnum), value)) Then Throw New ArgumentOutOfRangeException() End If _value = value RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Value")) End Set End Property#Region "INotifyPropertyChanged メンバー" Public Event PropertyChanged(sender As Object, e As ComponentModel.PropertyChangedEventArgs) _ Implements ComponentModel.INotifyPropertyChanged.PropertyChanged#End RegionEnd Class

データを表す列挙体とクラス(上:C#、下:VB)「SampleData」クラスには、UIコントロールとデータバインディングするために、INotifyPropertyChangedインタフェース(System.ComponentModel名前空間)を実装してある。

 このデータをテキストブロックにバインドして「One」「Two」「Three」と表示するのは簡単だ。テキストブロックのTextプロパティにデータバインディングするだけである(次のコード)。

<StackPanel x:Name="RadioButtonGroup1" ……省略…… > <TextBlock ……省略…… Text="{Binding Value}" /></StackPanel>

データをバインドするテキストブロック(XAML)ここでは、スタックパネルの中にテキストブロックを配置した。このスタックパネルには、次のコードでデータコンテキストにデータを設定する。

public MainWindow(){ InitializeComponent(); // データバインディングする RadioButtonGroup1.DataContext = new SampleData();}

Public Sub New() InitializeComponent() ' データバインディングする RadioButtonGroup1.DataContext = New SampleData()End Sub

「SampleData」インスタンスをデータバインディングする(上:C#、下:VB)ウィンドウのコンストラクタに、太字の部分を追加する。

 では、ラジオボタンの状態をデータバインディングしてみよう。前述したように、データの側にも三つの選択肢に対応した三つの真偽値型プロパティを用意すればよい(次のコード)。

public class SampleData : System.ComponentModel.INotifyPropertyChanged{ ……省略…… public SampleEnum Value { get { return _value; } set { ……省略…… var handler = PropertyChanged; _value = value; if (handler != null) { handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Value")); handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Is1")); handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Is2")); handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Is3")); } } } public bool Is1 { get { return Value == SampleEnum.One; } set { if (value) Value = SampleEnum.One; else Value = SampleEnum.Undefined; } } ……省略……}

Public Class SampleData Implements System.ComponentModel.INotifyPropertyChanged ……省略…… Public Property Value As SampleEnum Get Return _value End Get Set(value As SampleEnum) ……省略…… _value = value RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Value")) RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Is1")) RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Is2")) RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Is3")) End Set End Property Public Property Is1 As Boolean Get Return Value = SampleEnum.One End Get Set(value As Boolean) If (value) Then Me.Value = SampleEnum.One Else Me.Value = SampleEnum.Undefined End If End Set End Property ……省略……End Class

データに真偽値型プロパティを三つ追加する(上:C#、下:VB)追加した三つのプロパティのうち、「Is1」プロパティのみを示す。同様にして、「Is2」「Is3」も実装する。また、太字で示したように、「Value」プロパティのセッターにもコードを追加する。コードの全体は、別途公開のサンプルをご覧いただきたい。

 そして、次のコードのようにラジオボタンとバインドする。

<StackPanel x:Name="RadioButtonGroup1" ……省略…… > <RadioButton Tag="1" Content="選択肢1" IsChecked="{Binding Is1}" /> <RadioButton Tag="2" Content="選択肢2" IsChecked="{Binding Is2}" /> <RadioButton Tag="3" Content="選択肢3" IsChecked="{Binding Is3}" /> ……省略…… <TextBlock ……省略…… /> ……省略……</StackPanel>

データをバインドするラジオボタン(XAML)前述したテキストブロックと同じスタックパネル内に、ラジオボタンを三つ追加した。コードの全体は、別途公開のサンプルをご覧いただきたい。

 これで実行してみると次の画像のようになる。ラジオボタンの選択を変えるとデータに反映され、その値がデータバインディングでテキストブロックに表示されている。

ラジオボタンの選択を変えるとデータに反映されるラジオボタンの選択を変えるとデータに反映されるこの画像は、[選択肢2]のラジオボタンをクリックしたところ。その変化がバインドされている「SampleData」クラスに反映され、その結果として「SampleData」クラスをバインドしているテキストブロックの表示も「Two」に変化している。この方法の欠点

 この方法は簡単ではあるが、このままではデータの変更をラジオボタンに反映できない。

 画面にボタンを追加し、そのクリックイベントでデータを変更するようにしてみよう(次のコード)。

<StackPanel x:Name="RadioButtonGroup1" ……省略…… > <RadioButton Tag="1" Content="選択肢1" IsChecked="{Binding Is1}" /> ……省略…… <TextBlock ……省略…… /> ……省略…… <StackPanel Orientation="Horizontal" Margin="0,16,0,0"> <Button Click="SelectButton1_Click" Tag="1">1</Button> <Button Click="SelectButton1_Click" Tag="2">2</Button> <Button Click="SelectButton1_Click" Tag="3">3</Button> </StackPanel></StackPanel>

データ変更用のボタン(XAML)前述のコードに太字の部分を追加した。

private void SelectButton1_Click(object sender, RoutedEventArgs e){ string tag = (e.Source as Button).Tag as string; SampleEnum value = (SampleEnum)Enum.Parse(typeof(SampleEnum), tag); (RadioButtonGroup1.DataContext as SampleData).Value = value;}

Private Sub SelectButton1_Click(sender As Object, e As RoutedEventArgs) Dim tag As String = CType(CType(e.Source, Button).Tag, String) Dim value As SampleEnum _ = CType([Enum].Parse(GetType(SampleEnum), tag), SampleEnum) CType(RadioButtonGroup1.DataContext, SampleData).Value = valueEnd Sub

クリックされたボタンに応じてデータを変更する(上:C#、下:VB)ボタンのTagプロパティには「1」「2」「3」という数字が設定されている。ボタンクリックのイベントハンドラ(=このコード)で、Tagプロパティの値を「SampleEnum」列挙型に変換し、データバインドされている「SampleData」クラスの「Value」プロパティにセットする。これで、ボタンに応じた値にデータが変更されると、そのデータの変化がラジオボタンに反映されるはずなのだ(実際には、次に述べるような不具合が発生する)。

 実行してみると、次のような不具合が現れるはずだ。ボタンを[1]→[2]→[3]とクリックするだけでなく、[2]→[1]や[1]→[3]などと、しばらく操作を続けてみてほしい。

しばらく操作を続けるとバインディングが機能しなくなる(.NET 3.5)選択されているものより上の選択肢を1回で選択状態にできない(.NET 4.0以降)問題の回避策

 この問題を回避するには、データを切り替えるときに、いったん範囲外の値にすればよい(次のコード)。

public SampleEnum Value{ get { return _value; } set { ……省略…… var handler = PropertyChanged; // いったん範囲外の値にする _value = SampleEnum.Undefined; if (handler != null) { handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Is1")); handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Is2")); handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Is3")); } _value = value; if (handler != null) { handler.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs("Value")); ……省略…… } }}

Public Property Value As SampleEnum Get Return _value End Get Set(value As SampleEnum) ……省略…… ' いったん範囲外の値にする _value = SampleEnum.Undefined RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Is1")) RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Is2")) RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Is3")) _value = value RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Value")) ……省略…… End SetEnd Property

不具合を回避するコード(上:C#、下:VB)「SampleData」クラスの「Value」プロパティのセッターに、太字の部分を追記する。

 これでデータの変更が正しくラジオボタンに反映されるようになる。

 とはいうものの、データの側でバインディング先のコントロールの都合を考慮するというのはおかしなものだ。上の回避策はバインディング先がラジオボタンだから必要なのであって、例えばチェックボックスならば不要なのだ。そこが気になるようであれば、コンバータを使う方法を検討してほしい(ただし、.NET 4以降)。

まとめ

 ラジオボタンの選択状態をデータに反映させるには、データバインディングを使う。簡易的には、ラジオボタンの選択状態に対応する真偽値のプロパティをデータのクラスに追加すればよい。ただし、この方法では逆にデータの変化をラジオボタンの選択状態に反映させようとすると、不具合の回避策が必要になる。

利用可能バージョン:.NET Framework 3.5以降カテゴリ:WPF 処理対象:データバインディングカテゴリ:WPF/XAML 処理対象:RadioButtonコントロール使用ライブラリ:RadioButtonコントロール(System.Windows.Controls名前空間)使用ライブラリ:INotifyPropertyChangedインタフェース(System.ComponentModel名前空間)関連TIPS:WPF/UWP:ラジオボタンの選択をコードから切り替えるには?[C#/VB]

■この記事と関連性の高い別の.NET TIPSWPF/UWP:ラジオボタンの選択をコードから切り替えるには?[C#/VB]WPF/UWP:ラジオボタンを双方向バインディングするには?[C#/VB]WPF/UWP:テキストブロックの一部分だけをデータバインディングするには?[XAML]WPF:DataGridやListViewなどに表示しているデータを別スレッドから変更するには?[ASP.NET AJAX]PopupControlコントロールで標準コントロールにポップアップ機能を追加するには?「.NET TIPS」のインデックス

「.NET TIPS」

仮想通貨カジノパチンコau 電気 新規

コメントを残す