为WPF程序中的数据(Model)添加编辑功能

简介:

WPF的数据绑定是一个很强大的功能,TwoWay的绑定模式,让程序员不用编写一行代码,就可以实现程序界面(UI)与后台数据的同步。比如说后台数据的People.Name属性变化了,程序界面中显示People.Name的文本框控件就自动更新,反过来,文本框里面的数据被用户编辑了以后,后台数据的People.Name也自动更新成编辑过后的数据。很好,很强大,但问题是,如果用户在程序界面上更改文本框中的文本后,想取消编辑操作(Undo功能)怎么办?

一般来说,编辑数据的程序界面至少有两个按钮,例如下图:

用户在界面上做出修改以后,点击“确定”按钮,程序才会将内存中对象实例的数据更新成程序界面上的数据,点击“取消”的话,程序界面上的数据就丢掉了,内存中的对象不会发生任何改变。

然而数据绑定的TwoWay模式的功能太强大了,强大到根本不给我们“取消”的机会,只要用户的鼠标脱离文本框(例如“姓名”文本框),People.Name属性的数据就自动更新了。哼……那就不要用TwoWay模式了,用OneWay模式好了。使用OneWay模式,在创建编辑界面的时候,用户点击“确定”按钮的时候,编写类似的代码把UI的数据搬到对象上:

People.Name = nameTextBox.Text;

People.Birthday = DateTime.Parse(birthdayTextbox.Text);

呃……这样解决方案好像要为程序中每个对象编写类似的代码,也不是很好。

有没有办法即使用TwoWay的绑定模式,这样我们就不需要编写代码手工维护界面的数据和内存中对象实例的数据的同步工作了,然而同时又能提供回滚(Undo)的操作呢?经过一阵子搜索和研究之后,我发现WPF的数据绑定功能实际上是通过TypeDescriptor实现的,WPF数据绑定通过TypeDescriptor来发现一个类型里面定义了什么属性(原理我会在后续的文章里讲到), TypeDescriptor允许程序员插入一个自定义的TypeDescriptor。于是解决方案的思路:

1.       定义一个通用的ModelBase<T>类,用来封装任意一个可以在WPF 程序中编辑的数据(数据类型就是泛型参数T)。

2.       ModelBase<T>实现了IEditableObject接口,这个接口的定义如下:

namespace System.ComponentModel

{

    // Summary:

    //     Provides functionality to commit or rollback changes to an object that is

    //     used as a data source.

    public interface IEditableObject

    {

        // Summary:

        //     Begins an edit on an object.

        void BeginEdit();

        //

        // Summary:

        //     Discards changes since the last System.ComponentModel.IEditableObject.BeginEdit()

        //     call.

        void CancelEdit();

        //

        // Summary:

        //     Pushes changes since the last System.ComponentModel.IEditableObject.BeginEdit()

        //     or System.ComponentModel.IBindingList.AddNew() call into the underlying object.

        void EndEdit();

    }

}

 

ModelBase<T>类型实现了IEditableObject接口后,在WPF 程序里面,就可以在前台使用TwoWay的绑定模式,用户在界面上修改完数据后,“确定”按钮的事件处理函数只需要调用类似下面的代码,就可以将修改提交:

private void OkButton_OnClick(object sender, RoutedEventArgs e)

{

    ((IEditableObject)DataContext).EndEdit();

}

 

而“取消”按钮的事件处理函数只需要调用CancelEdit函数就可以取消修改了:

private void CancelButton_OnClick(object sender, RoutedEventArgs e)

{

    ((IEditableObject)DataContext).CancelEdit();

}

 

3.       ModelBase<T>通过提供一个自定义的TypeDescriptor,将定义在其内部封装的真实数据对象的属性合并到自己的类型里面,也就是说,当WPF通过在一个ModelBase<People>的实例上查询定义在类型PeopleName属性的时候,可以查询到这个属性。对于WPF来说,Name属性是直接定义在ModelBase<People>里面的,因为我们自定义的TypeDescriptor欺骗了WPF的数据绑定代码(当然这是WPF的数据绑定故意被骗的,周瑜打黄盖 ,一个愿打,一个愿挨)。

4.       当用户在程序界面上修改某个属性(比如Name属性)的值的时候,WPF的数据绑定将值传给ModelBase<T>实例,ModelBase<T>实例将这个属性的值先缓存起来,并不是直接将封装的实例的属性值修改。

5.       EndEdit函数调用的时候,ModelBase<T>这时才将缓存的修改刷新到封装的实例上。如果CancelEdit函数被调用,ModelBase<T>直接将缓存的修改丢掉,这样封装的实例并不会看到用户的修改。

这里是整个项目的源代码,其中ViewModel文件夹里面的代码是关键代码,下一篇文章再注释里面的关键代码。

/Files/killmyday/EditableObject.zip



本文转自 donjuan 博客园博客,原文链接:http://www.cnblogs.com/killmyday/archive/2009/12/07/1618278.html   ,如需转载请自行联系原作者

相关文章
|
2月前
|
C# 机器学习/深度学习 搜索推荐
WPF与机器学习的完美邂逅:手把手教你打造一个具有智能推荐功能的现代桌面应用——从理论到实践的全方位指南,让你的应用瞬间变得高大上且智能无比
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)应用中集成机器学习功能,以开发具备智能化特性的桌面应用。通过使用Microsoft的ML.NET框架,本文演示了从安装NuGet包、准备数据集、训练推荐系统模型到最终将模型集成到WPF应用中的全过程。具体示例代码展示了如何基于用户行为数据训练模型,并实现实时推荐功能。这为WPF开发者提供了宝贵的实践指导。
29 0
|
2月前
|
传感器 C# 监控
硬件交互新体验:WPF与传感器的完美结合——从初始化串行端口到读取温度数据,一步步教你打造实时监控的智能应用
【8月更文挑战第31天】本文通过详细教程,指导Windows Presentation Foundation (WPF) 开发者如何读取并处理温度传感器数据,增强应用程序的功能性和用户体验。首先,通过`.NET Framework`的`Serial Port`类实现与传感器的串行通信;接着,创建WPF界面显示实时数据;最后,提供示例代码说明如何初始化串行端口及读取数据。无论哪种传感器,只要支持串行通信,均可采用类似方法集成到WPF应用中。适合希望掌握硬件交互技术的WPF开发者参考。
40 0
|
2月前
|
开发者 C# UED
WPF与多媒体:解锁音频视频播放新姿势——从界面设计到代码实践,全方位教你如何在WPF应用中集成流畅的多媒体功能
【8月更文挑战第31天】本文以随笔形式介绍了如何在WPF应用中集成音频和视频播放功能。通过使用MediaElement控件,开发者能轻松创建多媒体应用程序。文章详细展示了从创建WPF项目到设计UI及实现媒体控制逻辑的过程,并提供了完整的示例代码。此外,还介绍了如何添加进度条等额外功能以增强用户体验。希望本文能为WPF开发者提供实用的技术指导与灵感。
74 0
|
2月前
|
存储 开发者 C#
WPF与邮件发送:教你如何在Windows Presentation Foundation应用中无缝集成电子邮件功能——从界面设计到代码实现,全面解析邮件发送的每一个细节密武器!
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中集成电子邮件发送功能,详细介绍了从创建WPF项目到设计用户界面的全过程,并通过具体示例代码展示了如何使用`System.Net.Mail`命名空间中的`SmtpClient`和`MailMessage`类来实现邮件发送逻辑。文章还强调了安全性和错误处理的重要性,提供了实用的异常捕获代码片段,旨在帮助WPF开发者更好地掌握邮件发送技术,提升应用程序的功能性与用户体验。
36 0
|
2月前
|
C# 开发者 Windows
WPF与PDF文档:解锁创建和编辑PDF文件的新技能——从环境配置到代码实践,手把手教你如何在WPF应用中高效处理PDF,提升文档管理效率
【8月更文挑战第31天】随着数字文档的普及,PDF因跨平台兼容性和高保真度成为重要格式。WPF虽不直接支持PDF处理,但借助第三方库(如iTextSharp)可在WPF应用中实现PDF的创建与编辑。本文通过具体案例和示例代码,详细介绍了如何在WPF中集成PDF库,并展示了从设计用户界面到实现PDF创建与编辑的完整流程。不仅包括创建新文档的基本步骤,还涉及在现有PDF中添加页眉页脚等高级功能。通过这些示例,WPF开发者可以更好地掌握PDF处理技术,提升应用程序的功能性和实用性。
45 0
|
2月前
|
API C# Shell
WPF与Windows Shell完美融合:深入解析文件系统操作技巧——从基本文件管理到高级Shell功能调用,全面掌握WPF中的文件处理艺术
【8月更文挑战第31天】Windows Presentation Foundation (WPF) 是 .NET Framework 的关键组件,用于构建 Windows 桌面应用程序。WPF 提供了丰富的功能来创建美观且功能强大的用户界面。本文通过问题解答的形式,探讨了如何在 WPF 应用中集成 Windows Shell 功能,并通过具体示例代码展示了文件系统的操作方法,包括列出目录下的所有文件、创建和删除文件、移动和复制文件以及打开文件夹或文件等。
45 0
|
2月前
|
C# Windows 监控
WPF应用跨界成长秘籍:深度揭秘如何与Windows服务完美交互,扩展功能无界限!
【8月更文挑战第31天】WPF(Windows Presentation Foundation)是 .NET 框架下的图形界面技术,具有丰富的界面设计和灵活的客户端功能。在某些场景下,WPF 应用需与 Windows 服务交互以实现后台任务处理、系统监控等功能。本文探讨了两者交互的方法,并通过示例代码展示了如何扩展 WPF 应用的功能。首先介绍了 Windows 服务的基础知识,然后阐述了创建 Windows 服务、设计通信接口及 WPF 客户端调用服务的具体步骤。通过合理的交互设计,WPF 应用可获得更强的后台处理能力和系统级操作权限,提升应用的整体性能。
65 0
|
2月前
|
C# 开发者 数据处理
WPF开发者必备秘籍:深度解析数据网格最佳实践,轻松玩转数据展示与编辑大揭秘!
【8月更文挑战第31天】数据网格控件是WPF应用程序中展示和编辑数据的关键组件,提供排序、筛选等功能,显著提升用户体验。本文探讨WPF中数据网格的最佳实践,通过DevExpress DataGrid示例介绍其集成方法,包括添加引用、定义数据模型及XAML配置。通过遵循数据绑定、性能优化、自定义列等最佳实践,可大幅提升数据处理效率和用户体验。
49 0
|
2月前
|
数据处理 开发者 C#
WPF数据绑定实战:从零开始,带你玩转数据与界面同步,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据绑定是核心技能之一,它能实现界面元素与数据源的同步更新。本文详细介绍了WPF数据绑定的概念与实现方法,包括属性绑定、元素绑定及路径绑定等技术,并通过示例代码展示了如何创建数据绑定。通过数据绑定,开发者不仅能简化代码、提高可维护性,还能提升用户体验。无论初学者还是有经验的开发者,都能从中受益,更好地掌握WPF数据绑定技巧。
33 0
|
2月前
|
开发框架 前端开发 JavaScript
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(10) -- 在DataGrid上直接编辑保存数据
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(10) -- 在DataGrid上直接编辑保存数据