none
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;
    …}

    2019年5月21日 2:54

回答

  • 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!)

    • 編集済み gekkaMVP 2019年5月21日 4:36 なぜか黄色のゴミが付く…
    • 回答としてマーク Akirakira 2019年5月21日 4:43
    2019年5月21日 4:25

すべての返信

  • 実際にバインドしているのはDataクラスですから、Dataクラスの内容が変わったことを通知する必要があります。つまり、DataクラスにINotifyPropertyChangedの実装が必要となります。

    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    2019年5月21日 3:36
    モデレータ
  • 「Dictionaryを更新」というのは具体的にどういう操作でしょうか?

    // データソースにDictionaryは使いづらいと思う…。

    2019年5月21日 3:36
  • ご回答ありがとうございます。

    DataClassにInotifyPropertyChangedを実装してみましたが、

    変わりませんでした。


    また、書き間違えて申し訳ないのですが、

    DataクラスはDataContainerクラスのメンバです。

    2019年5月21日 4:19
  • 情報が足らず申し訳ありません。

    Dictionaryを更新というのは

    Dictionary.Clear();

    Dictionary[Key] = new List<Data>();

    Dictionary[Key].Add(new Data());

    をしています。

    2019年5月21日 4:25
  • 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!)

    • 編集済み gekkaMVP 2019年5月21日 4:36 なぜか黄色のゴミが付く…
    • 回答としてマーク Akirakira 2019年5月21日 4:43
    2019年5月21日 4:25
  • gekkaさんの方法で期待通りの動作を得られました。

    ありがとうございました。

    trapemiyaさん、Hongliangさんもご回答いただきありがとうございました。

    2019年5月21日 4:45