トップ回答者
文字列の双方向バインディング?

質問
-
Bindingに関する質問です。
「ObservableCollection」をリスト表示して内容の変更も行う、という処理をBindingを使って実現しようとしていたのですが、データの表示はできるようになったのですが変更ができなくて困っています。
実際のコードは以下のような感じです。
Code SnippetXAML
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBox Text="{Binding Path=.,Mode=TwoWay}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ListBox Margin="40" ItemsSource="{Binding}" >
</ListBox>
<Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="94" Height="33" Content="Button" Click="Button_Click"/>
</Grid>C#
public Window1(){
this.InitializeComponent();
ObservableCollection<string> collection = new ObservableCollection<string>();
collection.Add("AAAA");
collection.Add("BBBB");
this.DataContext = collection;
}private void Button_Click(object sender, RoutedEventArgs e) {
string mes = "";
ObservableCollection<string> collection = (ObservableCollection<string>)this.DataContext;
foreach (string s in collection) {
mes += s + "\n";
}
MessageBox.Show(mes);
}テキストボックスの内容を変更してボタンを押すと現在リストに表示されている内容がメッセージボックスに出る、という動作を期待しているのですが・・。
stringを「stringを返すクラス」にしてあげれば実現できることは分かったのですが、できればstringのままで実現したいのです。実現方法がありましたら、教えていただけますでしょうか。
よろしくお願いします。
回答
-
MS の WPF のコードを覗いてみると,
INotifyPropertyChanged の実装は,以下のパターンになっている(揃えている?)ようです。
Code Snippetclass StringWrapper : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public String Text
{
get { return this._string; }
set
{
if (this._string == value) { return; }
this._string = value;
OnPropertyChanged("Text");
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
private void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
private String _string;
}
class StringWrapperCollection : ObservableCollection<StringWrapper> { }
-
プロパティを依存関係プロパティにしても実現可能だと思います。
Code Snippetpublic class StringClass : DependencyObject
{
#region ValueProperty
/// <summary>
/// Value 依存関係プロパティを識別します。
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
(
"Value",
typeof(string),
typeof(StringClass)
);
/// <summary>
/// 文字列の値を取得または設定します。
/// </summary>
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
#endregion
}
ところで、モデルを上記のように DependencyObject ベースにしたほうがよい場合は、どのような場合でしょうか?
ご存知の方は教えてください。
すべての返信
-
自己レスです。
今は以下のような感じでやってます。
Code SnippetXAML
<!--TextBoxのBinding Pathを変更-->
<TextBox Text="{Binding Path=Value,Mode=TwoWay}"/>
C#
public Window1() {
this.InitializeComponent();StringCollection collection = new StringCollection();
collection.Add("AAAA");
collection.Add("BBBB");this.DataContext = collection;
}private void Button_Click(object sender, RoutedEventArgs e) {
string mes = "";
StringCollection collection = (StringCollection)this.DataContext;
foreach (StringClass s in collection) {
mes += s.Value + "\n";
}
MessageBox.Show(mes);
}public class StringClass {
private string _value;
public StringClass(string s) {
_value = s;
}
public string Value {
get { return this._value; }
set { this._value = value; }
}
}public class StringCollection : ObservableCollection<StringClass> {
public void Add(string s) {
base.Add(new StringClass(s));
}
}
StringClassというクラスを作ってそのコレクションをBindingしてます。
一応実現できてはいるのですが、これでいいのか悪いのか・・・自信がありません。上記方法に対する意見やその他の解決策等ありましたらぜひお願いします。
-
yayadonさんありがとうございます。
Code Snippetpublic class StringClass : INotifyPropertyChanged {
private string _value;
public event PropertyChangedEventHandler PropertyChanged;public StringClass(string s) {
_value = s;
}
public string Value {
get { return this._value; }
set {
this._value = value;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(this._value));
}
}
}
}こんな感じでしょうか?
-
MS の WPF のコードを覗いてみると,
INotifyPropertyChanged の実装は,以下のパターンになっている(揃えている?)ようです。
Code Snippetclass StringWrapper : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public String Text
{
get { return this._string; }
set
{
if (this._string == value) { return; }
this._string = value;
OnPropertyChanged("Text");
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
private void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
private String _string;
}
class StringWrapperCollection : ObservableCollection<StringWrapper> { }
-
プロパティを依存関係プロパティにしても実現可能だと思います。
Code Snippetpublic class StringClass : DependencyObject
{
#region ValueProperty
/// <summary>
/// Value 依存関係プロパティを識別します。
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
(
"Value",
typeof(string),
typeof(StringClass)
);
/// <summary>
/// 文字列の値を取得または設定します。
/// </summary>
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
#endregion
}
ところで、モデルを上記のように DependencyObject ベースにしたほうがよい場合は、どのような場合でしょうか?
ご存知の方は教えてください。 -
こんにちは。森田 知良です。
回答を寄せてくださったみなさん、大変有用な情報をありがとうございました。
puniさん、フォーラムのご利用ありがとうございます。
私の方で回答をくださったみなさんの情報は、有用な情報と判断しましたので、
勝手ながら回答済みチェックをつけさせていただきました。回答済みチェックがつくことにより、有用な情報を探している方が情報を見つけやすくなります。
有効な回答があった場合は、なるべく回答済みボタンを押してチェックを付けてくださるようお願いします。なお、puniさんの意図しない回答にチェックが付いていた場合は、
回答済みチェックを解除することもできますのでご確認ください。
それでは、これからもフォーラムのご利用をよろしくお願いいたします。