zoukankan      html  css  js  c++  java
  • 在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象

    在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>
  • 相关阅读:
    .NET Framework 4.5 中新增的'可移植类库'功能
    使用visual sutdio右键菜单封装字段
    Visual Studio 2008的“组织using”菜单
    HTML5与HTML4的区别
    【百度地图API】如何制作公交线路的搜索?如331路
    【百度地图API】如何给自定义覆盖物添加事件
    【百度地图API】如何制作自定义样式的公交导航结果面板?
    【百度地图API】如何制作可拖拽的沿道路测距
    透过【百度地图API】分析双闭包问题
    【百度地图API】如何用圆形搜索获取中心点周围100米内全部关键点?如天安门附近所有的餐厅、加油站、宾馆、大厦等
  • 原文地址:https://www.cnblogs.com/bincoding/p/8549263.html
Copyright © 2011-2022 走看看