トップ回答者
DataGrid内のレコード更新の方法

質問
-
前回も同じような質問をしたのですが、やはりわからないので教えてください。質問は2つあります。
1.下記のプログラムを実行しButton2を押してlistデータの内容を更新したのですが、DataGridの表示が変わってくれません。
Bindingがわかってないだけだと思うのですが、具体的な実現方法を教えていただけないでしょうか。
2.DataGrid1 のみlistデータの内容を表示したいです。ItemsSource= をどのように指定すればよいのでしょうか?
みなさんにとってはとても簡単なことだと思うのですが、私にはわかりません。ご存じの方、どうかご教授よろしくお願いします。
================================ Window1.xaml ================================ <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="403" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"> <Grid> <my:DataGrid ItemsSource="{Binding}" AutoGenerateColumns="True" Margin="12,12,185,103" Name="dataGrid1" /> <my:DataGrid ItemsSource="{Binding}" AutoGenerateColumns="True" Margin="0,12,10,100" Name="dataGrid2" HorizontalAlignment="Right" Width="153" /> <Button Height="34" HorizontalAlignment="Left" Margin="41,0,0,37"
OS: Vista Home Premium
Name="button1" VerticalAlignment="Bottom" Width="78"
Click="button1_Click">登録</Button> <Button Height="38" HorizontalAlignment="Right" Margin="0,0,54,33"
Name="button2" VerticalAlignment="Bottom" Width="68"
Click="button2_Click">データ更新</Button> </Grid> </Window> ================================ Window1.xaml.cs ================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using WpfApplication1; namespace WpfApplication1 { /// <summary> /// Window1.xaml の相互作用ロジック /// </summary> public partial class Window1 : Window { public static List<Person> _list; public Window1() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { _list = new List<Person>(); _list.Add(new Person() { Name = "麻生 太郎", Age = 10 }); _list.Add(new Person() { Name = "山田 優", Age = 20 }); DataContext = _list; } private void button2_Click(object sender, RoutedEventArgs e) { _list[0].Name="オードリー春日"; DataContext = _list; MessageBox.Show(_list[0].Name + " " + _list[0].Age + "\r" + _list[1].Name + " " + _list[1].Age ); } } } ================================ Person.cs ================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WpfApplication1 { public class Person { public string Name { get; set; } public int Age { get; set; } } }
言語: C#
開発環境: Microsoft Visual C# 2008 Express Edition
.NET 3.5 SP1
回答
-
下記のプログラムを実行しButton2を押してlistデータの内容を更新したのですが、DataGridの表示が変わってくれません。
バインディングしているオブジェクトが、INotifyPropertyChanged インターフェイスを実装してプロパティ変更時に PropertyChanged イベントを発生させているか、あるいはそのオブジェクトが DependencyObject から派生したクラスでそのプロパティが依存関係プロパティとして公開されている必要があります。XAML に直接記述するようなものでない限り、INotifyPropertyChanged の方が一般的でしょう。
ito_ito さんのコードの場合、DataGrid の各行にバインドされている Person クラスのオブジェクトがこの場合の「バインドしているオブジェクト」に当たります。つまり、Person クラスに INotifyPropertyChanged インターフェイスを実装させ、Name 及び Age プロパティの set 内で PropertyChanged を発生させてください。具体的なコーディングについては MSDN または VS のヘルプで INotifyPropertyChanged インターフェイスの解説及びサンプルコードをご覧ください。
なお、DataGrid の ItemsSource にはコレクションをバインドしますが、もしこのコレクションへの要素の追加・削除を DataGrid に反映させたい場合、コレクションが INotifyCollectionChanged インターフェイスまたは IBindingList インターフェイスを実装する必要があります。INotifyCollectionChanged インターフェイスを実装した汎用クラスとして ObservableCollection<T> が 標準で用意されており、List<T> の代わりに使用することが可能です。DataGrid1 のみlistデータの内容を表示したいです。ItemsSource= をどのように指定すればよいのでしょうか?
ご質問の意図が今ひとつつかめませんが。
DataGrid2 に表示したくないなら、DataGrid2 の ItemsSource を特に設定しなければいいでしょう。
DataGrid1 と DataGrid2 で別々のリストを表示したいのなら、各リストのプロパティを持ったクラス(例えば Products プロパティと Customers プロパティを持った Company クラス、みたいなの)を用意し、それを Window の DataContext に設定し、それぞれのプロパティ名を各 DataGrid.ItemsSource の Binding の Path に設定すればいいです。- 回答としてマーク ito_ito 2009年12月27日 12:43
-
public class Person : INotifyPropertyChanged { #region INotifyPropertyChanged メンバ public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } #endregion private string _name; public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } } private int _age; public int Age { get { return _age; } set { _age = value; OnPropertyChanged("Age"); } } }
INotifyPropertyChanged インターフェイス はこんな感じです。
項目変更の反映はこれで出来ます。
えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12- 回答としてマーク ito_ito 2009年12月27日 12:43
-
なんとなく動きました。なんで、private string _name; private int _age;
private ReadOnlyObservableCollection<Person> _observalPersonList;
のprivateがでてくるのでしょう???もう少し調べてみます。
private は他のクラスからアクセスできないようにする指定です。
このプロパティ指定は省略形です。
public string Name { get; set; }
以下のコードと同じことです。
private string _name; public string Name { get { return _name; } set { _name = value; } }
えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12- 回答としてマーク ito_ito 2009年12月30日 16:33
すべての返信
-
下記のプログラムを実行しButton2を押してlistデータの内容を更新したのですが、DataGridの表示が変わってくれません。
バインディングしているオブジェクトが、INotifyPropertyChanged インターフェイスを実装してプロパティ変更時に PropertyChanged イベントを発生させているか、あるいはそのオブジェクトが DependencyObject から派生したクラスでそのプロパティが依存関係プロパティとして公開されている必要があります。XAML に直接記述するようなものでない限り、INotifyPropertyChanged の方が一般的でしょう。
ito_ito さんのコードの場合、DataGrid の各行にバインドされている Person クラスのオブジェクトがこの場合の「バインドしているオブジェクト」に当たります。つまり、Person クラスに INotifyPropertyChanged インターフェイスを実装させ、Name 及び Age プロパティの set 内で PropertyChanged を発生させてください。具体的なコーディングについては MSDN または VS のヘルプで INotifyPropertyChanged インターフェイスの解説及びサンプルコードをご覧ください。
なお、DataGrid の ItemsSource にはコレクションをバインドしますが、もしこのコレクションへの要素の追加・削除を DataGrid に反映させたい場合、コレクションが INotifyCollectionChanged インターフェイスまたは IBindingList インターフェイスを実装する必要があります。INotifyCollectionChanged インターフェイスを実装した汎用クラスとして ObservableCollection<T> が 標準で用意されており、List<T> の代わりに使用することが可能です。DataGrid1 のみlistデータの内容を表示したいです。ItemsSource= をどのように指定すればよいのでしょうか?
ご質問の意図が今ひとつつかめませんが。
DataGrid2 に表示したくないなら、DataGrid2 の ItemsSource を特に設定しなければいいでしょう。
DataGrid1 と DataGrid2 で別々のリストを表示したいのなら、各リストのプロパティを持ったクラス(例えば Products プロパティと Customers プロパティを持った Company クラス、みたいなの)を用意し、それを Window の DataContext に設定し、それぞれのプロパティ名を各 DataGrid.ItemsSource の Binding の Path に設定すればいいです。- 回答としてマーク ito_ito 2009年12月27日 12:43
-
public class Person : INotifyPropertyChanged { #region INotifyPropertyChanged メンバ public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } #endregion private string _name; public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } } private int _age; public int Age { get { return _age; } set { _age = value; OnPropertyChanged("Age"); } } }
INotifyPropertyChanged インターフェイス はこんな感じです。
項目変更の反映はこれで出来ます。
えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12- 回答としてマーク ito_ito 2009年12月27日 12:43
-
Hongliang様
えムナウ様
ご回答ありがとうございます!はっきり言って、よくわかっていないのですが、いろいろなサイトを参考に試行錯誤を繰り返していたら、
なんとなく動きました。なんで、private string _name; private int _age;
private ReadOnlyObservableCollection<Person> _observalPersonList;
のprivateがでてくるのでしょう???もう少し調べてみます。
とりあえず、できたソースを載せます!!
ご回答ありがとうございます!!すごく助かりました!
=================================== Window1.xaml =================================== <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="403" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"> <Grid> <my:DataGrid AutoGenerateColumns="True" Margin="12,12,185,103" Name="dataGrid1" /> <my:DataGrid AutoGenerateColumns="True" Margin="0,12,10,100" Name="dataGrid2" HorizontalAlignment="Right" Width="153" /> <Button Height="34" HorizontalAlignment="Left" Margin="41,0,0,37" Name="button1" VerticalAlignment="Bottom" Width="78" Click="button1_Click">登録</Button> <Button Height="38" HorizontalAlignment="Right" Margin="0,0,54,33" Name="button2" VerticalAlignment="Bottom" Width="68" Click="button2_Click">データ更新</Button> </Grid> </Window> =================================== Window1.xaml.cs =================================== using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using WpfApplication1; using System.Collections.ObjectModel; using System.ComponentModel; namespace WpfApplication1 { /// <summary> /// Window1.xaml の相互作用ロジック /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private ReadOnlyObservableCollection<Person> _observalPersonList; public ReadOnlyObservableCollection<Person> ObservalPersonList { get { return _observalPersonList; } set { if (_observalPersonList != value) { _observalPersonList = value; } } } private void button1_Click(object sender, RoutedEventArgs e) { var list = new ObservableCollection<Person>(); list.Add(new Person() { Name = "麻生 太郎", Age = 10 }); list.Add(new Person() { Name = "山田 優", Age = 20 }); ObservalPersonList = new ReadOnlyObservableCollection<Person>(list); dataGrid1.ItemsSource = ObservalPersonList; } //public event PropertyChangedEventHandler PropertyChanged; private void button2_Click(object sender, RoutedEventArgs e) { ObservalPersonList[0].Name = "オードリー春日"; MessageBox.Show(ObservalPersonList[0].Name + " " + ObservalPersonList[0].Age + "\r" + ObservalPersonList[1].Name + " " + ObservalPersonList[1].Age); } } } =================================== Person.cs =================================== using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; namespace WpfApplication1 { public class Person : INotifyPropertyChanged { #region INotifyPropertyChanged メンバ public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } #endregion private string _name; public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } } private int _age; public int Age { get { return _age; } set { _age = value; OnPropertyChanged("Age"); } } } }
-
なんとなく動きました。なんで、private string _name; private int _age;
private ReadOnlyObservableCollection<Person> _observalPersonList;
のprivateがでてくるのでしょう???もう少し調べてみます。
private は他のクラスからアクセスできないようにする指定です。
このプロパティ指定は省略形です。
public string Name { get; set; }
以下のコードと同じことです。
private string _name; public string Name { get { return _name; } set { _name = value; } }
えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12- 回答としてマーク ito_ito 2009年12月30日 16:33