天天看點

在WPF應用程式中利用IEditableObject接口實作可撤銷編輯的對象Model:EmployeeViewModel:

原文: 在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 這個例子,你可以通過  http://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>      

繼續閱讀