DataBindings 与 INotifyPropertyChanged 实现自动刷新 WinForm 界面
--首发于博客园, 转载请保留此链接 博客原文地址
业务逻辑与界面的分离对于维护与迁移是非常重要的,在界面上给某属性赋值,后台要检测到其已经发生变化
问题:
输入某物品 单价 Price, 数量Amount, 要求自动计算总价,即: TotalPrice = Price * Amount, 如下图:
普通的实现方式
TextBox.TextChanged() 事件中可以检测到值发生改变,并且可以给其他的 TextBox.Text 赋值,但是如果 TextBox 太多,给每个 TextBox 加这样的一个事件工作量会比较大。
下面介绍另外一种方法:
使用 DataBindings 与 INotifyPropertyChanged 配合可以轻松实现这个需求。
Step 1. 先写一个类 NotifyPropertyChanged 继承 INotifyPropertyChanged 实现 OnPropertyChanged , 当界面添加 PropertyChanged 的事件时可以实现刷新
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public bool SuppressNotifyPropertyChanged { get; set; }
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null && !SuppressNotifyPropertyChanged)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
} protected virtual void OnPropertyChanged<T>(Expression<Func<T>> expr)
{
this.OnPropertyChanged(Utils.GetMemberName(expr));
} /// <summary>
/// 如果没有其他的业务逻辑,对 lambda 表达式比较熟悉的同学可以考虑用以下方法实现属性名称传递
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propField"></param>
/// <param name="value"></param>
/// <param name="expr"></param>
protected void SetProperty<T>(ref T propField, T value, Expression<Func<T>> expr)
{
var bodyExpr = expr.Body as System.Linq.Expressions.MemberExpression;
if (bodyExpr == null)
{
throw new ArgumentException("Expression must be a MemberExpression!", "expr");
}
var propInfo = bodyExpr.Member as PropertyInfo;
if (propInfo == null)
{
throw new ArgumentException("Expression must be a PropertyExpression!", "expr");
}
var propName = propInfo.Name;
propField = value;
this.OnPropertyChanged(propName);
} } public class Utils
{
public static string GetMemberName<T>(Expression<Func<T>> expr)
{
var bodyExpr = expr.Body as System.Linq.Expressions.MemberExpression;
if (bodyExpr == null)
return string.Empty;
return bodyExpr.Member.Name;
}
}
Step 2. 写一个类 实现 Price, Amount, TotalPrice 的逻辑, 当然这个类继承 NotifyPropertyChanged
public class TestBindingClass : NotifyPropertyChanged
{
#region Properties private decimal _price; public decimal Price
{
get { return _price; }
set
{
_price = value;
_totalPrice = Amount * Price;
OnPropertyChanged(() => this.Price);
OnPropertyChanged(() => this.TotalPrice);
}
} private decimal _amount; public decimal Amount
{
get { return _amount; }
set
{
_amount = value;
_totalPrice = Amount * Price;
OnPropertyChanged(() => this.Amount);
OnPropertyChanged(() => this.TotalPrice);
}
} private decimal _totalPrice; public decimal TotalPrice
{
get { return _totalPrice; }
set
{
_totalPrice = value;
if (Amount != 0)
_price = TotalPrice / Amount; // Note:don't call method Price_Set, or it goes into an infinite loop
OnPropertyChanged(() => this.TotalPrice);
OnPropertyChanged(() => this.Price);
}
} #endregion
}
Step 3. 界面绑定相关属性,这样就给相关的属性加了 PropertyChanged 事件
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
textBox1.DataBindings.Add(ControlBindingProperty.Text, myClass, () => myClass.Price);
textBox2.DataBindings.Add(ControlBindingProperty.Text, myClass, () => myClass.Amount);
textBox3.DataBindings.Add(ControlBindingProperty.Text, myClass, () => myClass.TotalPrice);
} TestBindingClass myClass = new TestBindingClass();
} public static class GUIUtils
{
public static void Add<T>(this ControlBindingsCollection bindings, string propertyName, object dataSource, Expression<Func<T>> expr)
{
string dataMember = Utils.GetMemberName(expr);
bindings.Add(propertyName, dataSource, dataMember);
}
} public static class ControlBindingProperty
{
public const string Text = "Text";
}
总结:
(1). 在其他属性的 set 方法里给其他属性赋值时最好用小写的属性名,而不要直接调用 OtherProperty_set 方法, 否则容易进入死循环
(2). 可以看到step 3 里,添加了 ControlBindingsCollection 的扩展方法,这样就不用担心"PropertyName" 之类容易出错的看起来很恶心的写法,事实上 IDE 的提示功能使 lambda 表达式写起来非常方便,并且在 Build 的时候就可以查出属性名是否对应,提高写代码的效率,减少出错的机会
DataBindings 与 INotifyPropertyChanged 实现自动刷新 WinForm 界面的更多相关文章
- 使用线程操作刷新Winform界面
主窗体中添加代码 public FrmMain() { InitializeComponent(); System.Threading.Thread thread = new System.Threa ...
- sublime3安装liveload,实现前端自动F5刷新html界面
这两天倒腾编辑器,atom实在太大了,还是sublime好用 以前一直用sublime2, 然后更新到sublime3, 然后把一些必要的插件安装了一下:liveload(自动刷新): package ...
- C# Winform频繁刷新导致界面闪烁解决方法
C#Winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供的默认双缓冲将 ...
- winform频繁刷新导致界面闪烁解决方法
转自龙心文 原文 winform频繁刷新导致界面闪烁解决方法 一.通过对窗体和控件使用双缓冲来减少图形闪烁(当绘制图片时出现闪烁时,使用双缓冲) 对于大多数应用程序,.NET Framework 提供 ...
- Web界面和Winform界面生成,代码生成工具
在上面一篇随笔<代码生成工具之界面快速生成>介绍了代码生成工具Database2Sharp的界面生成操作,其中介绍了Web界面(包括列表界面.内容显示.内容编辑界面的生成,另外还介绍了Wi ...
- NanUI for Winform发布,让Winform界面设计拥有无限可能
如今,尽管WPF.UWP大行其道,大有把Winform打残干废的趋势.但是还是有那么一波顽固不化的老家伙们固守着Winform,其中就包括我. 好吧,既然都说Winform做得软件不如WPF界面美观效 ...
- 告诉你吧,一套皮肤在winform与wpf开发模式下实现的界面效果同样精彩,winform界面和wpf界面。
一.同一资源: 二.先上软件界面: (1)wpf界面: 在wpf中实现这样类似web风格的软件界面就不用我多说了,在wpf实现这样的风格是很简单的,完全像网页设计一样的. (2)winform界面 在 ...
- 循序渐进开发WinForm项目(4)--Winform界面模块的集成使用
随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...
- 自动刷新ALV
转自http://blog.sina.com.cn/s/blog_701594f40100l8ms.html ABAP:利用SAP定时器自动刷新ALV 曾于无意之中发现,SAP系统中有个名为CL_GU ...
随机推荐
- android离线下载的相关知识
离线下载的功能点如下: 1.下载管理(开始.取消下载). 2.网络判断(Wi-Fi,3G). 3.独立进程. 4.定时和手机催醒. 5.自启动. 选择 ...
- C#自定义List类
代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespac ...
- getParameter百科
获取数据库中的参数数据 getParameter(). request.getParameter("username");其中的这个username 是接受前台的参数 比如in ...
- Asp.Net WebApi+Microsoft.AspNet.WebApi.Core 启用CORS跨域访问
WebApi中启用CORS跨域访问 1.安装 Nugget包Microsoft.AspNet.WebApi.Cors This package contains the components to e ...
- Jquery 使用JSOPN实例
1.说明 dataType:返回的数据类型 jsonp:传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) jsonpCallback:自定义的jsonp ...
- 序列化和持久化 merge方法和saveOrUpdate方法
merge方法和saveOrUpdate方法的区别 merge方法是把我们提供的对象转变为托管状态的对象:而saveOrUpdate则是把我们提供的对象变成一个持久化对象:说的通俗一点就是:saveO ...
- 难搞的Android开发环境(sdk 代理)
概述 搞了近一周的环境搭建,在csdn上提个问,有位网友说弄一下代理,搜一下,果真有人写博客:Android SDK代理服务器解决国内不能更新下载问题 其实我下了很多个集成好的 adt-bundle- ...
- Arcgis - Personal Geodatabase 和 File Geodatabase的区别.
一.平台支持: 1.Personal Geodatabase:仅可在Windows 上运行: 2.File Geodatabase:跨平台支持,可在Windows 及UNIX.linux上运行. 评 ...
- FileDirLocationOperator - 文件或目录位置操作.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Move ...
- magent——memcached缓存代理服务器
memcached分布式缓存 我们使用PHP连接多台memcached服务器,做分布式缓存,实现如下: $memcache = new Memcache; $memcache->addServe ...