2

簡単なものが欠けていると思いますが、基本的には複数のステップでデータを取得しています。例で行っていることのより単純なバージョンを見てみましょう。

  1. INotifyPropertyChanged を実装する監視可能なコレクションがあります
  2. Observable Collection は、次の 2 つのプロパティを構成する単純な POCO クラスである「POCO」クラスです。

    PersonID int { get; set; }
    Name string { get; set; }
    
  3. POCO クラスに同じメタ値を含む単純なデータベース テーブルをマップするエンティティから SQL データ モデルへのエンティティがあり、単純な例として、3 つの行の値があるとします。

    PersonID, Name
    1,  Brett
    2,  Emily
    3,  Test
    
  4. 監視可能なコレクションは、ModelView で次のように配線されます。

    ObservableCollection<POCO> _Pocos;
    POCOEntities ee = new POCOEntities();
    
    public ObservableCollection<POCO> POCOs
    {
        get
        {
            if (_Pocos == null)
            {
                List<POCO> mes = this.GetPOCOs();
                _Pocos= new ObservableCollection<POCO>(mes);
            }
    
            return _Pocos;
        }
        set
        {
            _Pocos = value;
    
            OnPropertyChanged("POCOs");
        }
    }
    
    List<POCO> GetPOCOs()
    {
        return ee.vPOCO.Select(p => new POCOView()
            {
                PersonId = p.PersonID,
                Name = p.Name
            }).ToList();
    }
    
  5. また、現在のアイテムをそのように配線しています。

    POCO _CurrentPOCO;
    
    public POCO CurrentPOCO
    {
        get { return _CurrentPOCO; }
        set
        {
            _CurrentPOCO = value;
    
            OnPropertyChanged("CurrentPOCO");
        }
    }
    
  6. 4 と 5 は ModelView の根幹であり、データグリッドのビューにそれらを次のように結び付けます。

     <DataGrid x:Name="datagrid" 
          ItemsSource="{Binding POCOs}" 
          CurrentItem="{Binding CurrentPOCO}" />
    
  7. これは私が理解できない部分です。データベースのエンティティ モデルをほぼリアルタイムで更新するにはどうすればよいですか? コレクションは正常に接続され、更新されています。何が起こったのかをデータベースに伝えるにはどうすればよいですか? 「CellEditEnding」や「SelectionChanged」などのイベントを設定し、エンティティ モデルから Update proc を実装しようとすると、ModelView で BOMBS になります。背後にあるコードだけに固執すると、動作しますが、「変更後」の値をキャプチャしていないようです。

ICommand プロパティを使用し、MVVM で実行されるリレー コマンドを実装しても。これらの方法は機能しません。それで、私がそれを考えすぎていて、データベースを更新するだけで焼き込めるある種のインターフェースがあるかどうかに興味がありました。ドキュメントの挿入を処理してから、メソッドを使用してデータグリッドを設定または更新できますが、datagridview の値を変更してデータベースを直接更新できるようにしたいと考えています。

概要: 可能な限り簡単な方法で、datagridview と observablecollection を変更してデータベースを更新し、2 つが互いに同期するようにしたいだけです。

4

4 に答える 4

2

ここでは、2 つのカテゴリの変更があります。

  1. コレクションが変更されます。つまり、アイテムが追加および/または削除されます。これらの変更を追跡するには、VM でObservableCollectionCollectionChangedイベントをリッスンし、NewItemsおよびOldItemsプロパティを使用して、DB に追加または削除するデータを特定します。
  2. 人の名前を変更するなど、POCO インスタンスの 1 つのプロパティが変更されます。CollectionChangedコレクション自体は同じままであるため、このような変更はイベントをトリガーしません。

#2 では、POCO クラスのプロパティの更新を処理する単純な Viewmodel を実装します。結局のところ、POCO はビジネス オブジェクトと見なされるべきであり、ビューに直接公開されるべきではありません。各 PocoVM は、単一の POCO インスタンスへの参照を保持します。

編集

あなたが何を使用していて、どのように機能するのかわからないため、スタブ化されたデータベースを除いて、実験で使用したコードを多かれ少なかれすべて追加しました。アイテムのリストを返し、単一のアイテムを更新するように指示できる限り、それは実際には問題ではありません。

XAML MysticalDBLayer によって受け入れられた変更を表示するために別のグリッド (読み取り専用) を追加したことを除いて、あなたのものと同じです。また、編集中のアイテムを追跡するためCurrentItemに を使用するPocoVM

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="Auto"/>
        <RowDefinition />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <TextBlock>Input-Grid</TextBlock>
    <DataGrid Grid.Row="1"
              ItemsSource="{Binding POCOs}"/>
    
    <TextBlock Grid.Row="2">Readonly-Grid</TextBlock>
    <DataGrid Grid.Row="3"
              ItemsSource="{Binding POCOs, Mode=OneWay}"
              IsReadOnly="True"/>
</Grid>

ビュー モデル (XAML の DataContext) このファイルに入れるのはこれだけです。データベース接続は使用するものによって異なる場合がありますが、基本的には、POCO ごとに新しい PocoVM (ビューモデル) を作成し、新しい PocoVMを POCO のObservableCollection代わりに自体

class VM
{
    ObservableCollection<PocoVM> _pocoCollection = new ObservableCollection<PocoVM>();

    public ObservableCollection<PocoVM> POCOs
    {
        get
        {
            if (_pocoCollection.Count == 0)
            {
                _pocoCollection = new ObservableCollection<PocoVM>();
                IEnumerable<POCO> pocos = MysticalDBLayer.GetItems();
                foreach (POCO poco in pocos)
                {
                    _pocoCollection.Add(new PocoVM(poco));
                }
            }
            return _pocoCollection;
        }
    }
}

そして最後に PocoVM セルの 1 つの値を更新しようとするたびに (Numbergetter しかないため、このコードでは name のみ update:able になります)、対応する setter がこのクラスで呼び出されます。ここで、DB への書き込みを行い、それがうまくいったかどうかに基づいて行動することができます。

class PocoVM : INotifyPropertyChanged
{
    private POCO _dataInstance = null;

    public PocoVM(POCO dataInstance)
    {
        _dataInstance = dataInstance;
    }

    public uint Number
    {
        get { return _dataInstance.Number; }
    }

    public string Name
    {
        get { return _dataInstance.Name; }
        set
        {
            if (string.Compare(value, _dataInstance.Name, StringComparison.CurrentCultureIgnoreCase) == 0)
                return;

            if (!MysticalDBLayer.UpdatePoco(_dataInstance, new POCO(_dataInstance.Number, value)))
                return;

            _dataInstance.Name = value;
            OnPropertyChanged("Name");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string property)
    {
        if (PropertyChanged == null)
            return;

        PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
}
于 2013-02-14T14:36:10.260 に答える
0

私があなたを正しく理解していれば、 ObservableCollectionのCollectionChangedイベントを使用するだけで済みます。

イベント引数にはアクション(追加/削除...) が含まれており、NewItemsOldItemsも取得できます。

したがって、コレクションの変更を追跡し、データベースとの同期を行うことができます。お役に立てれば幸いです。

于 2013-02-11T05:21:06.450 に答える
0

ObservableCollectionオーバーライドInsertItem()RemoveItem()メソッドを独自に作成します。

public class CustomerCollection : ObservableCollection<Customer>
{
    private DataContext _db;

    public DataContext Db
    {
      get { return _db; }
    }

    public CustomerCollection(IEnumerable<Customer> customers, DataContext context)
      : base(customers)
    {
      _db = context;
    }

    protected override void InsertItem(int index, Customer item)
    {
      this.Db.AddToCustomers(item);
      this.Db.SaveChanges();
      base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
      this.Db.DeleteObject(this[index]);
      this.Db.SaveChanges();
      base.RemoveItem(index);
    }

}
于 2013-02-11T05:30:10.983 に答える
-1

これは、ここで回答したばかりの質問に似ていますWPF datagrid with MVVM。(当サイト初心者のため、回答を転載させていただきます)

ListCollectionViewを使用する必要があります。

これを行う方法を示すサンプルを次に示します。

1) ListCollectionViewTestという名前の新しい WPF プロジェクトを作成します。

2) MainWindow.xaml.cs で、以下をカット アンド ペーストします (ViewModel にあるはずですが、私は面倒です)。

    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;

    namespace ListCollectionViewTest
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private List<Employee> equivalentOfDatabase = new List<Employee>()
                        {
                            new Employee() { FirstName = "John", LastName = "Doe", IsWorthyOfAttention = true },
                            new Employee() { FirstName = "Jane", LastName = "Doe", IsWorthyOfAttention = true },
                            new Employee() { FirstName = "Mr.", LastName = "Unsignificant", IsWorthyOfAttention = false },
                        };

            public ListCollectionView TestList { get; set; }
            public MainWindow()
            {
                DataContext = this;

                // This is all the magic you need -------
                TestList = new ListCollectionView(equivalentOfDatabase);
                TestList.Filter = x => (x as Employee).IsWorthyOfAttention;

                InitializeComponent();
            }

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                MessageBox.Show(equivalentOfDatabase.Aggregate("Employees are: \n\r", (acc, emp) => acc + string.Format("    - {0} {1}\n\r", emp.FirstName, emp.LastName), x => x));
            }
        }

        public class Employee
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public bool IsWorthyOfAttention { get; set; }
        }
    }

3) MainWindow.xaml で、これをカット アンド ペーストします。

    <Window x:Class="ListCollectionViewTest.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">

        <StackPanel>
            <DataGrid ItemsSource="{Binding TestList}"
                      RowHeight="22"
                      AutoGenerateColumns="True">
            </DataGrid>
            <Button Content="Show All Employees in DB" Click="Button_Click" />
        </StackPanel>        
    </Window>
于 2013-02-13T19:42:38.840 に答える