wpf 使用实体框架实现 MVVM 模式 - 添加删除

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14955378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 07:37:21  来源:igfitidea点击:

Implementing the MVVM Pattern with Entity Framework - Add Removing

c#wpfentity-frameworkmvvm

提问by Mohtaa

I'm trying to implement the MVVM Pattern on my WPF project that uses Entity Framework to get / manipulates data. I'm confused, i want to know where validating changes on my collections of model objects to database should be??? my application is as follow : in my view i've a datagrid of persons, two textboxes that will load the name / surname of the selected person , a buton to updated changes of rows and a button to delete the selected row.

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

In my ModelView , i have an observableCollection that will be loaded at the initilization of the class with information from my database ( entities) + two Relaycommands for Add/Remove buttons ( please find the code below).

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

The problem is that i didn't understood well the philosophy of MVVM, where and when and how modifications on my data should be pushed to database? For now, when i update a row in my database, and save my DB context modifications on my observable collection are submitted, but it's not the cdase when i remove an item, i've to manually look for it in database and remove it ( i've attached my observablecollection to a NotifyCollectionChangedEventHandler event that will handle this)... i don't get the point of using Observable collection!!!

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

Is there any simple explanation of a "perfect" mvvm architecture using database data??? Thanks! my ViewModel

是否有使用数据库数据的“完美”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();
        }
    }
}

My model

我的模型

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

My XAML

我的 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>

回答by user663470

I don't have an answer to why you aren't seeing your expected results but I thought I would give you some ideas on how to structure this a bit better.

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

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.

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

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).

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

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.

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

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.

例如,不是说 new DeleteCommandHandler(),您可以要求控制反转容器(例如 Structure Map)来构建它。

ObjectFactory.GetInstance<DeleteCommandHandler>();

Then your DeleteCommandHandler class could look like

然后你的 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;
    }
}

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

抱歉有点含糊,要解释的太多了,这里有点晚了。阅读命令模式http://en.wikipedia.org/wiki/Command_pattern

回答by silverfighter

I think there is not "THE" way in mvvm there are always several and like always it depends.

我认为 mvvm 中没有“THE”方式,总是有几种方式,而且总是视情况而定。

But the to your solution there is an interface called IDataErrorInfowhich can help you out.

但是对于您的解决方案,有一个名为的接口IDataErrorInfo可以帮助您解决问题。

For a example take a look at this article... http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM

例如,看看这篇文章... http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM

Or here: http://blindmeis.wordpress.com/2012/04/16/wpf-mvvm-idataerrorinfo-validation-errortemplate/

或在这里:http: //blindmeis.wordpress.com/2012/04/16/wpf-mvvm-idataerrorinfo-validation-errortemplate/

And maybe you should think about hiding entity framework from your view models with the repository pattern or a simply DataService.

也许您应该考虑使用存储库模式或简单的DataService.

hope that helps...

希望有帮助...