1

Entity Framework を使用してデータを取得/操作する WPF プロジェクトに MVVM パターンを実装しようとしています。私は混乱しています。データベースへのモデル オブジェクトのコレクションの変更を検証する場所を知りたいですか? 私のアプリケーションは次のとおりです。私のビューでは、人のデータグリッド、選択した人の名前/姓をロードする2つのテキストボックス、行の変更を更新するボタン、選択した行を削除するボタンがあります。

私の ModelView には、クラスの初期化時にデータベースからの情報 (エンティティ) + 追加/削除ボタン用の 2 つのリレーコマンド (以下のコードを見つけてください) を使用してロードされる observableCollection があります。

問題は、MVVM の哲学をよく理解していなかったことです。データの変更をいつ、どこで、どのようにデータベースにプッシュする必要がありますか? 今のところ、データベースの行を更新し、監視可能なコレクションに DB コンテキストの変更を保存すると、送信されますが、アイテムを削除するときに cdase ではないため、データベースで手動で検索して削除する必要があります (これを処理する NotifyCollectionChangedEventHandler イベントに observablecollection をアタッチしました)... Observable コレクションを使用するポイントがわかりません!!!

データベースデータを使用した「完璧な」mvvm アーキテクチャの簡単な説明はありますか? ありがとう!私のViewModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows;
using MVVMOK.Models;
using MVVMOK.Base;
using System.Collections.Specialized;

namespace MVVMOK.ViewModel
{
    class MainWindowViewModel : ViewModelBase
    {
        private DW_MargoEntities contexte;



        //Constructor
        public MainWindowViewModel()
        {
            contexte = new DATABASEEntities();
            collectionOfCollaborators = new ObservableCollection<Collaborator>();
            foreach (Collaborator c in contexte.Collaborator)
            {
                collectionOfCollaborators.Add(c);
            }


            //Abonnement pour l'ajout ou la suppression d'éléments :
            collectionOfCollaborators.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(collectionOfCollaboratorsChanged);

            //Assignation des commandes : 
            this._deleteComand = new RelayCommand(new Action<object>(DeleteRow));
            this._updateCommand = new RelayCommand(new Action<object>(UpdateDB));
        }
        //liste des propriétés publiques:


        //Propriété pour représenter l'élément séléctionné du datagrid
        private  Collaborator selectedItem;
        public Collaborator _selectedItem
        {
            get { return selectedItem; }
            set
            {
                if (value != selectedItem)
                {
                    selectedItem = value;
                    OnPropertyChanged("_selectedItem");
                };
            }
        }
        //Propriété pour représenter l'élément séléctionné:
        private ObservableCollection<Collaborator> collectionOfCollaborators;
        public ObservableCollection<Collaborator> _collectionOfCollaborators
        {
            get { return collectionOfCollaborators; }
            set
            {
                this.collectionOfCollaborators = value;
                OnPropertyChanged("_collectionOfCollaborators");
            }
        }

        //Commandes : 
        public ICommand _updateCommand
        {
            get;
            set;
        }
        public ICommand _deleteComand
        {
            get;
            set;
        }

        void collectionOfCollaboratorsChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            Collaborator f = new Collaborator();
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:

                    for(int i = 0; i<e.NewItems.Count;i++)
                    {

                        if (e.NewItems[i].GetType().Equals(f.GetType()))
                        {
                            contexte.Collaborator.Add(e.NewItems[i] as Collaborator);
                        }
                    }
                    contexte.SaveChanges();
                    break;

                case NotifyCollectionChangedAction.Remove:

                    for (int i = 0; i < e.OldItems.Count; i++)
                    {

                        if (e.OldItems[i].GetType().Equals(f.GetType()))
                        {
                            contexte.Collaborator.Remove(e.OldItems[i] as Collaborator);
                        }
                    }
                    contexte.SaveChanges();
                    break;
                //Reset = Clear

            }
        }



        //Services :
        public void UpdateDB(object msg)
        {
            contexte.SaveChanges();
        }


        public void DeleteRow(object msg)
        {

            _collectionOfCollaborators.Remove(_selectedItem);
            contexte.SaveChanges();
        }
    }
}

私のモデル

namespace MVVMOK.Models
{
    using System;
    using System.Collections.Generic;

    public partial class Collaborator
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
    }
}

マイ XAML

<Window x:Class="MVVMOK.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:MVVMOK.ViewModel"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <!-- Declaratively create an instance of our SongViewModel -->
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid Height="237" HorizontalAlignment="Left" Margin="12,12,0,0" Name="grid1" VerticalAlignment="Top" Width="479">
            <DataGrid AutoGenerateColumns="False" Height="237" HorizontalAlignment="Left" Name="dataGrid1" VerticalAlignment="Top" Width="479" ItemsSource="{Binding Path=_collectionOfCollaborators, Mode=TwoWay}" SelectionMode="Single" SelectedItem="{Binding Path=_selectedItem, Mode=TwoWay}"  >
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Path=Id}" Header="ID" />
                    <DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" Width="4*" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="104,255,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text ="{Binding Path=_selectedItem.Name, Mode=TwoWay}" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="104,283,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text ="{Binding Path=_selectedItem.Surname, Mode=TwoWay}" />
        <Label Content="Name" Height="28" HorizontalAlignment="Left" Margin="50,255,0,0" Name="label1" VerticalAlignment="Top" />
        <Label Content="Surname" Height="28" HorizontalAlignment="Left" Margin="37,283,0,0" Name="label2" VerticalAlignment="Top" />
        <Button Content="Delete Row" Height="23" HorizontalAlignment="Left" Margin="416,260,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Path=_deleteComand}"/>
        <Button Content="Update All" Height="23" HorizontalAlignment="Left" Margin="335,260,0,0" Name="button2" VerticalAlignment="Top" Width="75" Command="{Binding Path=_updateCommand}"/>
    </Grid>
</Window>
4

2 に答える 2

1

期待した結果が得られない理由についてはお答えできませんが、これをもう少しうまく構成する方法についていくつかのアイデアを提供したいと思います.

What you really want to do when data changes is apply a command. For instance the delete command should be applied. When handling this command you can perform any validation and either persist the change or flag an error. So your DeleteRow class which you have wrapped in the relay command should really be a separate class in a Model tier of your application. You can have a web tier that uses MVVM, but it should be persistence ignorant, it should apply a command and then react appropriately if the command succeeds or fails.

this._deleteComand = new RelayCommand(new Action<object>(DeleteRow));

could be something more like

this._deleteComand = new RelayCommand(new Action<object>() => {new DeleteCommandHandler().Apply(new DeleteCommand(){SelectedItem = _selectedItem})});

The DeleteCommandHandler and DeleteCommand will form part of your model (I would use a different class library for this).

Now your handlers need to know about your persistence mechanism, so inside your handler you can create your DW_MargoEntities context and do the work to delete.

The advantages of this is your view model is no longer responsible for updating your model so your view models will be a lot simpler and won't have a direct dependency on what database you use.

Once you have a command handler pattern setup I would move towards dependency injection for your context.

For instance rather than saying new DeleteCommandHandler(), you could ask an Inversion of Control container such as Structure Map to build it.

ObjectFactory.GetInstance<DeleteCommandHandler>();

Then your DeleteCommandHandler class could look like

class DeleteCommandHandler
{
    DW_MargoEntities context;
    public DeleteCommandHandler(DW_MargoEntities context)
    {
        this.context = context;
    }

    public bool Apply(DeleteCOmmand command)
    {
        if (not valid) {return false;}
        var item = context.LoadEntityById<EntityTypeHere>(command.SelectedItem) // Query the item

        context.Delete(item);
        return true;
    }
}

Sorry for being a bit vague, it's a lot to explain and it's getting a bit late here. Have a read on the command pattern http://en.wikipedia.org/wiki/Command_pattern

于 2013-02-19T11:48:53.777 に答える
0

mvvmには「THE」方法はなく、常にいくつかあり、常に依存していると思います。

しかし、あなたのソリューションには、あなたIDataErrorInfoを助けることができるというインターフェースがあります。

例については、この記事をご覧ください... http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM

またはここ: http://blindmeis.wordpress.com/2012/04/16/wpf-mvvm-idataerrorinfo-validation-errortemplate/

また、リポジトリ パターンまたは単にDataService.

それが役立つことを願っています...

于 2013-02-19T11:33:54.820 に答える