1

我正在尝试在我的 WPF 项目上实现 MVVM 模式,该项目使用实体框架来获取/操作数据。我很困惑,我想知道验证我的模型对象集合到数据库的更改应该在哪里???我的应用程序如下:在我看来,我有一个人员数据网格,两个文本框将加载所选人员的姓名/姓氏,一个更新行更改的按钮和一个删除所选行的按钮。

在我的 ModelView 中,我有一个 observableCollection,它将在类的初始化时加载,其中包含来自我的数据库(实体)的信息 + 两个用于添加/删除按钮的 Relaycommands(请在下面找到代码)。

问题是我没有很好地理解 MVVM 的理念,我的数据的修改应该在何时何地以及如何推送到数据库?现在,当我更新我的数据库中的一行,并将我的数据库上下文修改保存在我的 observable 集合上时,提交,但是当我删除一个项目时它不是 cdase,我必须在数据库中手动查找它并删除它(我已将我的 observablecollection 附加到将处理此问题的 NotifyCollectionChangedEventHandler 事件)...我不明白使用 Observable 集合的意义!

有没有使用数据库数据的“完美”mvvm架构的简单解释???谢谢!我的视图模型

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

对于您为什么没有看到预期结果,我没有答案,但我想我会给您一些关于如何更好地构建它的想法。

当数据更改时,您真正想做的是应用命令。例如,应该应用删除命令。处理此命令时,您可以执行任何验证并保留更改或标记错误。因此,您在中继命令中包装的 DeleteRow 类实际上应该是应用程序模型层中的一个单独类。您可以拥有一个使用 MVVM 的 Web 层,但它应该不了解持久性,它应该应用命令,然后在命令成功或失败时做出适当的反应。

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

可能更像是

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

DeleteCommandHandler 和 DeleteCommand 将构成您的模型的一部分(我将为此使用不同的类库)。

现在您的处理程序需要了解您的持久性机制,因此您可以在处理程序中创建 DW_MargoEntities 上下文并执行删除工作。

这样做的好处是您的视图模型不再负责更新您的模型,因此您的视图模型将简单得多,并且不会直接依赖于您使用的数据库。

一旦你有一个命令处理程序模式设置,我将转向你的上下文的依赖注入。

例如,与其说 new DeleteCommandHandler(),不如让一个 Inversion of Control 容器(例如 Structure Map)来构建它。

ObjectFactory.GetInstance<DeleteCommandHandler>();

然后你的 DeleteCommandHandler 类可能看起来像

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

抱歉有点含糊,要解释的东西很多,这里有点晚了。阅读命令模式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 回答