在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象
2013-08-26 09:27
369 查看
这是我辅导的一个项目开发中的例子,他们是用WPF做界面开发,在学习了如何使用MVVM来实现界面与逻辑的分离,并且很好的数据更新之后,有一个疑问就是,这种双向的数据更新确实很不错,但如果我们希望用户可以撤销修改怎么办呢?其实这个功能,很早就有,甚至在原先的Windows Forms里面也可以实现。秘密就是实现IEditableObject这个接口。
关于这个接口的官方文档在这里:http://msdn.microsoft.com/zh-cn/library/vstudio/system.componentmodel.ieditableobject.aspx
我做了一个小的例子,帮助大家来理解。该例子使用了MVVM这种设计模式,如果你对此不熟悉,请先参考:/article/4661010.html
这个例子,你可以通过 http://files.cnblogs.com/chenxizhang/WpfApplicationBindingSample.zip 进行下载
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
View:
关于这个接口的官方文档在这里:http://msdn.microsoft.com/zh-cn/library/vstudio/system.componentmodel.ieditableobject.aspx
我做了一个小的例子,帮助大家来理解。该例子使用了MVVM这种设计模式,如果你对此不熟悉,请先参考:/article/4661010.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() { //结束编辑,这里可以不做任何事情,也可以添加一些额外的逻辑 } } }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
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那个标签的文本恢复到原来的值 }); } } } }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
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>
相关文章推荐
- Java学习笔记——利用接口和observer实现对象监视
- 利用golang语法检查对象是否实现了接口
- 利用内核对象----互斥量实现应用程序只运行一个实例
- 利用比较接口实现List中的对象排序
- 利用比较接口实现List中的对象排序
- 利用比较接口实现List中的对象排序
- 利用golang语法检查对象是否实现了接口
- 适配器模式实现利用Scanner来扫描实现了Readable接口的对象
- 自己在项目中的学习总结:利用工厂模式+反射机制+缓存机制,实现动态创建不同的数据层对象接口
- 适配器模式实现利用Scanner来扫描实现了Readable接口的对象
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--类设计2
- WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
- .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务1[使用IE浏览本页]
- 利用 ICallbackEventHandler接口 实现客户端回调
- Delphi接口的底层实现(接口在内存中仍然有其布局,它依附在对象的内存空间中,有汇编解释)——接口的内存结构图,简单清楚,深刻 good
- 利用邮件对象实现发送QQ日志以及检测用户是否开通SMTP功能
- 实现百度下拉菜单实例(利用jsonp跨域请求百度数据接口)
- 【Java】-利用天气查询API实现天气预报小窗体应用程序(一)
- 利用java反射来实现输出对象的所有属性值
- 利用最小编辑距离算法实现文本diff