MVVM - 实施“IsDirty”功能可以将一个模型视图,以保存数据 [英] MVVM - implementing 'IsDirty' functionality to a ModelView in order to save data

查看:103
本文介绍了MVVM - 实施“IsDirty”功能可以将一个模型视图,以保存数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为新的WPF和放大器; MVVM我一些基本的功能挣扎。

Being new to WPF & MVVM I struggling with some basic functionality.

让我先解释我是什么之后,再附上一些示例代码...

Let me first explain what I am after, and then attach some example code...

我有一个显示的用户列表的屏幕,我显示在右侧与文本框编辑所选用户的详细信息。然后,我有一个保存按钮是数据绑定,但我会当数据实际上已经改变了只喜欢这个按钮可以显示。 ,即 - 我需要检查脏数据

I have a screen showing a list of users, and I display the details of the selected user on the right-hand side with editable textboxes. I then have a Save button which is DataBound, but I would only like this button to display when data has actually changed. ie - I need to check for "dirty data".

我有,我有一个模式叫用户完全MVVM例如:

I have a fully MVVM example in which I have a Model called User:

namespace Test.Model
{
    class User
    {
        public string UserName { get; set; }
        public string Surname { get; set; }
        public string Firstname { get; set; }
    }
}



然后,视图模型看起来是这样的:

Then, the ViewModel looks like this:

using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Input;
using Test.Model;

namespace Test.ViewModel
{
    class UserViewModel : ViewModelBase
    {
        //Private variables
        private ObservableCollection<User> _users;
        RelayCommand _userSave;

        //Properties
        public ObservableCollection<User> User
        {
            get
            {
                if (_users == null)
                {
                    _users = new ObservableCollection<User>();
                    //I assume I need this Handler, but I am stuggling to implement it successfully
                    //_users.CollectionChanged += HandleChange;

                    //Populate with users
                    _users.Add(new User {UserName = "Bob", Firstname="Bob", Surname="Smith"});
                    _users.Add(new User {UserName = "Smob", Firstname="John", Surname="Davy"});
                }
                return _users;
            }
        }

        //Not sure what to do with this?!?!

        //private void HandleChange(object sender, NotifyCollectionChangedEventArgs e)
        //{
        //    if (e.Action == NotifyCollectionChangedAction.Remove)
        //    {
        //        foreach (TestViewModel item in e.NewItems)
        //        {
        //            //Removed items
        //        }
        //    }
        //    else if (e.Action == NotifyCollectionChangedAction.Add)
        //    {
        //        foreach (TestViewModel item in e.NewItems)
        //        {
        //            //Added items
        //        }
        //    } 
        //}

        //Commands
        public ICommand UserSave
        {
            get
            {
                if (_userSave == null)
                {
                    _userSave = new RelayCommand(param => this.UserSaveExecute(), param => this.UserSaveCanExecute);
                }
                return _userSave;
            }
        }

        void UserSaveExecute()
        {
            //Here I will call my DataAccess to actually save the data
        }

        bool UserSaveCanExecute
        {
            get
            {
                //This is where I would like to know whether the currently selected item has been edited and is thus "dirty"
                return false;
            }
        }

        //constructor
        public UserViewModel()
        {

        }

    }
}



RelayCommand只是一个简单的包装类,由于是ViewModelBase。 (我会附上后者虽然只是为了清楚起见)

The "RelayCommand" is just a simple wrapper class, as is the "ViewModelBase". (I'll attach the latter though just for clarity)

using System;
using System.ComponentModel;

namespace Test.ViewModel
{
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
        protected ViewModelBase()
        { 
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        public void Dispose()
        {
            this.OnDispose();
        }

        protected virtual void OnDispose()
        {
        }
    }
}

最后 - 的XAML

Finally - the XAML

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:Test.ViewModel"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <vm:UserViewModel/>
    </Window.DataContext>
    <Grid>
        <ListBox Height="238" HorizontalAlignment="Left" Margin="12,12,0,0" Name="listBox1" VerticalAlignment="Top" 
                 Width="197" ItemsSource="{Binding Path=User}" IsSynchronizedWithCurrentItem="True">
            <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                        <TextBlock Text="{Binding Path=Firstname}"/>
                        <TextBlock Text="{Binding Path=Surname}"/>
                </StackPanel>
            </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Label Content="Username" Height="28" HorizontalAlignment="Left" Margin="232,16,0,0" Name="label1" VerticalAlignment="Top" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="323,21,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=User/UserName}" />
        <Label Content="Surname" Height="28" HorizontalAlignment="Left" Margin="232,50,0,0" Name="label2" VerticalAlignment="Top" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="323,52,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text="{Binding Path=User/Surname}" />
        <Label Content="Firstname" Height="28" HorizontalAlignment="Left" Margin="232,84,0,0" Name="label3" VerticalAlignment="Top" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="323,86,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" Text="{Binding Path=User/Firstname}" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="368,159,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Path=UserSave}" />
    </Grid>
</Window>



所以基本上,当我编辑的姓氏,保存按钮应该被启用。如果我取消我的编辑 - 。好那么就应该再作为一切都没有改变停用

So basically, when I edit a surname, the Save button should be enabled; and if I undo my edit - well then it should be Disabled again as nothing has changed.

我已经在许多例子中看到了这一点,但还没有找到如何做到这一点。

I have seen this in many examples, but have not yet found out how to do it.

任何帮助将不胜感激!
布兰登

Any help would be much appreciated! Brendan

推荐答案

在我的经验,如果实施 IsDirty 在您的视图模型,你可能也想视图模型实施 IEditableObject

In my experience, if you implement IsDirty in your view model, you probably also want the view model to implement IEditableObject.

假设你的视图模型是通常的排序,实施的PropertyChanged ,并引发它,设置私人或受保护的 OnPropertyChanged 方法 IsDirty 是很简单的:你刚才设置 IsDirty OnPropertyChanged 如果不是已经成为事实。

Assuming that your view model is the usual sort, implementing PropertyChanged and a private or protected OnPropertyChanged method that raises it, setting IsDirty is simple enough: you just set IsDirty in OnPropertyChanged if it isn't already true.

IsDirty 二传手应该,如果财产是假的,现在是真实的,调用 BeginEdit

Your IsDirty setter should, if the property was false and is now true, call BeginEdit.

保存命令应该叫 EndEdit中,这将更新数据模型和集 IsDirty 为假。

Your Save command should call EndEdit, which updates the data model and sets IsDirty to false.

取消命令应该叫的CancelEdit ,这刷新从数据模型,并设置视图模型 IsDirty 为假。

Your Cancel command should call CancelEdit, which refreshes the view model from the data model and sets IsDirty to false.

CanSave CanCancel 属性(假设你使用一个 RelayCommand 这些命令)只返回 IsDirty 。

The CanSave and CanCancel properties (assuming you're using a RelayCommand for these commands) just return the current value of IsDirty.

请注意,由于没有这功能取决于具体的实施视图模型,你可以把它放在一个抽象基类。派生类没有实现任何命令相关的属性或 IsDirty 财产;他们只需要重写 BeginEdit EndEdit中的CancelEdit

Note that since none of this functionality depends on the specific implementation of the view model, you can put it in an abstract base class. Derived classes don't have to implement any of the command-related properties or the IsDirty property; they just have to override BeginEdit, EndEdit, and CancelEdit.

这篇关于MVVM - 实施“IsDirty”功能可以将一个模型视图,以保存数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆