none
ObservableCollectionをバインドしたDataGridの更新 RRS feed

  • 質問

  • 現在C#2013のWPFでデータを取り扱うアプリを作成しています。

    データベースから取得したデータをObservableCollectionに追加後,DataGridにBindしています。

    Form上でデータベースにデータを追加したら、DataGridにも反映させたいのですが、方法がどうしても分かりません。

    OBservableCollectionにデータを追加する部分は以下のようになります。

    class view_ProgramList 


        {

            public ObservableCollection<View_Program> vProgram { get; set; }

            public view_ProgramList()
            {

                vProgram = new ObservableCollection<View_Program>();

       //DBに接続してデータを取得する自作のクラス
                DB_Utils dbu = new DB_Utils();
                OleDbDataReader dr = dbu.getReader("select no,path from test where no = 1);
                /////////////////////////////////////////////////

                while (dr.Read())
                {
                    View_Program uset = new View_Program();
                    uset.no = (string)dr.GetValue(0);
                    uset.path = dr.GetValue(2).ToString();
                    vProgram.Add(uset);

                }

                dr.Close();
            }
        }

    別のファイルにメンバー変数を定義しています。

            

    class View_Program 
        {

            public int no { get; set; }
            public string path { get; set; }

        }

    xamlでは以下のようにBindしています。

            <DataGrid Name="d1" 
                      AutoGenerateColumns="False" 
                      ItemsSource="{Binding Path=vProgram}" >

     <!-- textBoxの定義など... -->

    </DataGrid>

    MVVM及びWPFを始めたばかりで、プログラムや言葉の使い方が悪い部分もあるかと思いますが、

    何卒、ご助言をよろしくお願い致します。

    2015年3月10日 12:59

回答

  • 現状の実装ですと、
    DataGridが表示される前のデータしか表示されていないと思います。
    DataGridが表示された後に再描画等を行いたい場合は、vProgram内のアイテムを追加・削除・更新する必要があります。
    ObservableCollection<T>型となっているため、このコレクションの変更は通知処理を書かなくともDataGridへ通知されるはずです。

    参考として、コレクションの末尾にアイテムを追加するAddメソッドを追加してみました。

        class view_ProgramList
         {

            public ObservableCollection<View_Program> vProgram
            {
                get;
                set;
            }

             public view_ProgramList()
             {

                 vProgram = new ObservableCollection<View_Program>();
                 Add(new View_Program { no = 1, path = "test" });

             }

            public void Add(View_Program viewProgram)
            {
                vProgram.Add(viewProgram);
            }
         }

    -------------------
    (追記)
    コレクション内のアイテムの更新は、View_Program に変更通知の実装が必要になります。
    View_Program クラスにINotifyPropertyChangedインターフェースを実装するのがよく使われる手です。

    2015年3月10日 13:59
  • こんにちは。

    vProgramリストに対してアイテムの追加・削除をするだけでリストの増減はViewへ通知されます。
    なのでart55さんが仰っているように項目追加するだけで反映されます。

    DBから最新データを取得しリストを作り直す場合は一度クリアしてからリストを作成するか、
    リストのインスタンス自体を作り直すのであればvProgram自体に変更通知を実装すればよいです。

    [クリアするパターン]

    vProgram.Clear();
    vProgram.Add(new View_Program() { no = 0, path = "A" });
    vProgram.Add(new View_Program() { no = 1, path = "B" });
    vProgram.Add(new View_Program() { no = 2, path = "C" });
    vProgram.Add(new View_Program() { no = 3, path = "D" });
    

    [通知パターン]

    public class ViewModelBase : INotifyPropertyChanged
    {
        protected void OnPropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    public class view_ProgramList : ViewModelBase
    {
        private ObservableCollection<View_Program> _vProgram;
        public ObservableCollection<View_Program> vProgram
        {
            get
            {
                return _vProgram;
            }
            set
            {
                _vProgram = value;
                OnPropertyChanged("vProgram");
            }
        }
        private void AddNewData()
        {
            //...DB登録後
            vProgram = new ObservableCollection<View_Program>();
            vProgram.Add(new View_Program() { no = 0, path = "A" });
            vProgram.Add(new View_Program() { no = 1, path = "B" });
            vProgram.Add(new View_Program() { no = 2, path = "C" });
            vProgram.Add(new View_Program() { no = 3, path = "D" });
    
        }
    
        …省略…
    
    }
    

    方法がどうしてもわからないというのがどのへんがわからないのか明確になると、
    良い回答がつくと思います。

    2015年3月10日 14:38
    モデレータ

すべての返信

  • どのようにうまく行っていないのでしょうか? 現在の状況を教えていただくと、原因を推測しやすくなります。
    例えば、DataContextの設定はちゃんとされていますか? また、uset.path = dr.GetValue(2).ToString();となっていますが、2ではなくて1であったりしないでしょうか?
    なお、全体的な考え方自体は間違っていないので、どこかちょっとしたところが間違っているのだと思います。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2015年3月10日 13:35
    モデレータ
  • 現状の実装ですと、
    DataGridが表示される前のデータしか表示されていないと思います。
    DataGridが表示された後に再描画等を行いたい場合は、vProgram内のアイテムを追加・削除・更新する必要があります。
    ObservableCollection<T>型となっているため、このコレクションの変更は通知処理を書かなくともDataGridへ通知されるはずです。

    参考として、コレクションの末尾にアイテムを追加するAddメソッドを追加してみました。

        class view_ProgramList
         {

            public ObservableCollection<View_Program> vProgram
            {
                get;
                set;
            }

             public view_ProgramList()
             {

                 vProgram = new ObservableCollection<View_Program>();
                 Add(new View_Program { no = 1, path = "test" });

             }

            public void Add(View_Program viewProgram)
            {
                vProgram.Add(viewProgram);
            }
         }

    -------------------
    (追記)
    コレクション内のアイテムの更新は、View_Program に変更通知の実装が必要になります。
    View_Program クラスにINotifyPropertyChangedインターフェースを実装するのがよく使われる手です。

    2015年3月10日 13:59
  • こんにちは。

    vProgramリストに対してアイテムの追加・削除をするだけでリストの増減はViewへ通知されます。
    なのでart55さんが仰っているように項目追加するだけで反映されます。

    DBから最新データを取得しリストを作り直す場合は一度クリアしてからリストを作成するか、
    リストのインスタンス自体を作り直すのであればvProgram自体に変更通知を実装すればよいです。

    [クリアするパターン]

    vProgram.Clear();
    vProgram.Add(new View_Program() { no = 0, path = "A" });
    vProgram.Add(new View_Program() { no = 1, path = "B" });
    vProgram.Add(new View_Program() { no = 2, path = "C" });
    vProgram.Add(new View_Program() { no = 3, path = "D" });
    

    [通知パターン]

    public class ViewModelBase : INotifyPropertyChanged
    {
        protected void OnPropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    public class view_ProgramList : ViewModelBase
    {
        private ObservableCollection<View_Program> _vProgram;
        public ObservableCollection<View_Program> vProgram
        {
            get
            {
                return _vProgram;
            }
            set
            {
                _vProgram = value;
                OnPropertyChanged("vProgram");
            }
        }
        private void AddNewData()
        {
            //...DB登録後
            vProgram = new ObservableCollection<View_Program>();
            vProgram.Add(new View_Program() { no = 0, path = "A" });
            vProgram.Add(new View_Program() { no = 1, path = "B" });
            vProgram.Add(new View_Program() { no = 2, path = "C" });
            vProgram.Add(new View_Program() { no = 3, path = "D" });
    
        }
    
        …省略…
    
    }
    

    方法がどうしてもわからないというのがどのへんがわからないのか明確になると、
    良い回答がつくと思います。

    2015年3月10日 14:38
    モデレータ
  • 皆様

    アドバイスありがとうございました。

    ObservablaCollectionへのアイテムの追加を実行していないため、更新されていないことが原因でした。

    ご提示いただいた、下記のコードを参考にしたところ、問題なく更新できました。

    public void Add(View_Program viewProgram)
            {
                vProgram.Add(viewProgram);
            }


    2015年3月14日 2:54