トップ回答者
DictionaryをBindしたDataGridの表示が更新されない

質問
-
DictionaryをDataGridのItemSourceにしています。
以下の症状で困っています。
・最初に表示したときはGridに表示される
・Dictionaryを更新してもDataGrid内の表示が変わらない
・Dictionaryを更新後、DataGridをClickしてScrollしたりHeaderを押したりするとDataGrid内の表示が変わる
どなたかどこが間違っているのか教えていただければ幸いです。
何卒よろしくお願いいたします。
■XAML(抜粋)<Window…
<DataGrid Name="LogFileDataGrid" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Files, UpdateSourceTrigger=PropertyChanged}" AlternationCount="2">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Value/Name, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Date" Binding="{Binding Path=Value/Date, StringFormat=yyyy/MM/dd, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
</DataGrid>…</Window>
■ソースコード(抜粋)
public Class Data
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
public Class DataContainer : INotifyPropertyChanged
{…
Dictionary<string, List<Data>> _Dict;
public Files
{
set{_Dict = value;
OnPropertyChanged("Files");}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string info)
{
if (PropertyChanged != null) this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(info));
}
…}
public MainWindow()
{…
_Data = new DataContainer();
this.DataContext = _Data;
…}
回答
-
DictionaryからCollectoinViewを経由してやればDictionaryでも変更通知は一応できます。
<Window x:Class="WpfApp2.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:WpfApp2" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <DockPanel> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <Button Content="Test1" Click="Button1_Click" Margin="5"/> </StackPanel> <DataGrid Name="LogFileDataGrid" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Files, UpdateSourceTrigger=PropertyChanged}" AlternationCount="2"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Path=Value/Name, UpdateSourceTrigger=PropertyChanged}"/> <DataGridTextColumn Header="Date" Binding="{Binding Path=Value/Date, StringFormat=yyyy/MM/dd, UpdateSourceTrigger=PropertyChanged}"/> </DataGrid.Columns> </DataGrid> </DockPanel> </Grid> </Window>
namespace WpfApp2 { using System; using System.Linq; using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Data; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = _Data; } DataContainer _Data=new DataContainer(); private void Button1_Click(object sender, RoutedEventArgs e) { _Data.TestAdd(); } } public class Data : System.ComponentModel.INotifyPropertyChanged { public string Name { get { return _Name; } set { if (_Name != value) { _Name = value; OnPropertyChanged("Name"); } } } private string _Name; public DateTime Date { get { return _Date; } set { if (_Date != value) { _Date = value; OnPropertyChanged("Date"); } } } private DateTime _Date; #region INotifyPropertyChanged メンバ public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string name) { var pc = PropertyChanged; if (pc != null) { pc(this, new System.ComponentModel.PropertyChangedEventArgs(name)); } } #endregion } public class DataContainer : System.ComponentModel.INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string info) { if (PropertyChanged != null) this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(info)); } Dictionary<string, List<Data>> _Dict=new Dictionary<string, List<Data>>(); public System.ComponentModel.ICollectionView Files { get { return CollectionViewSource.GetDefaultView(_Dict); } } private void RaiseFilesCollectionChanged() { Files.Refresh(); } internal Dictionary<string, List<Data>> FilesInternal { get { return _Dict; } set { _Dict = value; OnPropertyChanged("Files"); } } public void TestAdd() { Random rnd = new Random(); if (_Dict.Count > 0) { _Dict.Values.Last()[0].Name = "B0"; _Dict.Values.Last()[1].Name = "B1"; } List<Data> list = new List<Data>(); for (int i = 0; i < 3; i++) { Data data = new Data(); data.Name = "A"; data.Date = DateTime.Now.AddDays(rnd.Next(5)); list.Add(data); } _Dict.Add(_Dict.Count.ToString(), list); RaiseFilesCollectionChanged(); } } }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
すべての返信
-
DictionaryからCollectoinViewを経由してやればDictionaryでも変更通知は一応できます。
<Window x:Class="WpfApp2.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:WpfApp2" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <DockPanel> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <Button Content="Test1" Click="Button1_Click" Margin="5"/> </StackPanel> <DataGrid Name="LogFileDataGrid" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Files, UpdateSourceTrigger=PropertyChanged}" AlternationCount="2"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Path=Value/Name, UpdateSourceTrigger=PropertyChanged}"/> <DataGridTextColumn Header="Date" Binding="{Binding Path=Value/Date, StringFormat=yyyy/MM/dd, UpdateSourceTrigger=PropertyChanged}"/> </DataGrid.Columns> </DataGrid> </DockPanel> </Grid> </Window>
namespace WpfApp2 { using System; using System.Linq; using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Data; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = _Data; } DataContainer _Data=new DataContainer(); private void Button1_Click(object sender, RoutedEventArgs e) { _Data.TestAdd(); } } public class Data : System.ComponentModel.INotifyPropertyChanged { public string Name { get { return _Name; } set { if (_Name != value) { _Name = value; OnPropertyChanged("Name"); } } } private string _Name; public DateTime Date { get { return _Date; } set { if (_Date != value) { _Date = value; OnPropertyChanged("Date"); } } } private DateTime _Date; #region INotifyPropertyChanged メンバ public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string name) { var pc = PropertyChanged; if (pc != null) { pc(this, new System.ComponentModel.PropertyChangedEventArgs(name)); } } #endregion } public class DataContainer : System.ComponentModel.INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string info) { if (PropertyChanged != null) this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(info)); } Dictionary<string, List<Data>> _Dict=new Dictionary<string, List<Data>>(); public System.ComponentModel.ICollectionView Files { get { return CollectionViewSource.GetDefaultView(_Dict); } } private void RaiseFilesCollectionChanged() { Files.Refresh(); } internal Dictionary<string, List<Data>> FilesInternal { get { return _Dict; } set { _Dict = value; OnPropertyChanged("Files"); } } public void TestAdd() { Random rnd = new Random(); if (_Dict.Count > 0) { _Dict.Values.Last()[0].Name = "B0"; _Dict.Values.Last()[1].Name = "B1"; } List<Data> list = new List<Data>(); for (int i = 0; i < 3; i++) { Data data = new Data(); data.Name = "A"; data.Date = DateTime.Now.AddDays(rnd.Next(5)); list.Add(data); } _Dict.Add(_Dict.Count.ToString(), list); RaiseFilesCollectionChanged(); } } }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)