在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象

这是我辅导的一个项目开发中的例子,他们是用WPF做界面开发,在学习了如何使用MVVM来实现界面与逻辑的分离,并且很好的数据更新之后,有一个疑问就是,这种双向的数据更新确实很不错,但如果我们希望用户可以撤销修改怎么办呢?其实这个功能,很早就有,甚至在原先的Windows Forms里面也可以实现。秘密就是实现IEditableObject这个接口。

关于这个接口的官方文档在这里:http://msdn.microsoft.com/zh-cn/library/vstudio/system.componentmodel.ieditableobject.aspx

 

我做了一个小的例子,帮助大家来理解。该例子使用了MVVM这种设计模式,如果你对此不熟悉,请先参考:http://www.cnblogs.com/chenxizhang/archive/2011/10/01/2197786.html

这个例子,你可以通过 https://files.cnblogs.com/chenxizhang/WpfApplicationBindingSample.zip 进行下载

Model:Employee

using System.ComponentModel;

namespace WpfApplicationBindingSample.Models
{
    /// <summary>
    /// 业务实体(Business Entity)
    /// </summary>
    class Employee : INotifyPropertyChanged,IEditableObject
    {
        private string _firstName;

        public string FirstName
        {
            get { return _firstName; }
            set
            {
                if (_firstName != value)
                {
                    _firstName = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
                        PropertyChanged(this, new PropertyChangedEventArgs("FullName"));
                    }
                }
            }
        }

        private string _lastName;
        public string LastName
        {
            get { return _lastName; }
            set
            {
                if (_lastName != value)
                {
                    _lastName = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("LastName"));
                        PropertyChanged(this, new PropertyChangedEventArgs("FullName"));
                    }
                }
            }
        }

        public string FullName
        {
            get
            {
                return FirstName + "," + LastName;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private Employee backup;//用这个字段来保存一个备份数据
        public void BeginEdit()
        {
            //开始编辑,此时将当前的状态保存起来,以便后续可以根据情况提交或者撤销更改
            backup = this.MemberwiseClone() as Employee;//通过克隆的方式直接地复制一份数据
        }

        public void CancelEdit()
        {
            //撤销编辑,此时将对象状态恢复到备份的状态
            this.FirstName = backup.FirstName;
            this.LastName = backup.LastName;
        }

        public void EndEdit()
        {
            //结束编辑,这里可以不做任何事情,也可以添加一些额外的逻辑
        }
    }
}

ViewModel:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Windows;
using WpfApplicationBindingSample.Models;

namespace WpfApplicationBindingSample.ViewModels
{
    /// <summary>
    /// 视图模型:专门用来为界面(视图)来服务的,这里用来包含一些业务逻辑
    /// </summary>
    class MainWindowViewModel : ViewModelBase
    {

        public MainWindowViewModel()
        {
            CurrentEmployee = new Employee()
            {
                FirstName = "ares",
                LastName = "chen"
            };
        }

        public Employee CurrentEmployee { get; set; }
        public RelayCommand EditCommand {
            get {
                return new RelayCommand(() => {
                    //将该员工设置为开始编辑
                    CurrentEmployee.BeginEdit();
                });
            }
        }

        /// <summary>
        /// 使用命令的机制代替了事件
        /// </summary>
        public RelayCommand SubmitCommand
        {
            get
            {//使用匿名方法
                return new RelayCommand(() =>
                {
                    //结束编辑,让更改生效
                    CurrentEmployee.EndEdit();

                    MessageBox.Show(CurrentEmployee.FullName);
                });
            }
        }

        public RelayCommand CancelCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    CurrentEmployee.CancelEdit();//取消编辑,此时可以看到FullName那个标签的文本恢复到原来的值
                });
            }
        }
    }
}

View:

<Window x:Class="WpfApplicationBindingSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:WpfApplicationBindingSample.ViewModels"
        Title="MainWindow"
        Height="350"
        Width="525">

    <Window.DataContext>
        <!--绑定数据上下文-->
        <vm:MainWindowViewModel></vm:MainWindowViewModel>
    </Window.DataContext>

    <Window.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Margin"
                    Value="3"></Setter>
        </Style>

        <Style TargetType="TextBox">
            <Setter Property="Width"
                    Value="200"></Setter>
            <Setter Property="HorizontalAlignment"
                    Value="Left"></Setter>
        </Style>

        <Style TargetType="Button">
            <Setter Property="Width"
                    Value="100"></Setter>
            <Setter Property="HorizontalAlignment"
                    Value="Left"></Setter>
        </Style>

    </Window.Resources>

    <StackPanel Margin="10">
        <TextBlock FontSize="30"
                   Text="编辑员工"></TextBlock>

        <TextBlock Text="姓氏"></TextBlock>
        <TextBox Text="{Binding CurrentEmployee.FirstName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>
        <!--匈牙利命名法-->
        <TextBlock Text="名称"></TextBlock>
        <TextBox Text="{Binding CurrentEmployee.LastName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>

        <TextBlock Text="全称"></TextBlock>
        <TextBlock Text="{Binding CurrentEmployee.FullName}"></TextBlock>

        <Button Content="编辑"
                Command="{Binding EditCommand}"></Button>
            <Button Content="提交"
                Command="{Binding SubmitCommand}"></Button>
        <Button Content="取消"
                Command="{Binding CancelCommand}"></Button>

    </StackPanel>

</Window>
posted @ 2013-08-26 09:27  陈希章  阅读(2995)  评论(0编辑  收藏  举报