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 ...
随机推荐
- C语音指针Introduction.
指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指针变量可以表示各种数据结构: 能很方便地使用数组和字符串: 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序 ...
- Json格式的http请求
服务端PHP代码可以从这里下载:https://github.com/lornajane/PHP-Web-Services 1.使用volley实现: request要用JsonObjectReque ...
- Linux命令之必杀绝技Vi文本编辑的使用
vi 文本编辑器 语法:vi [参数] 文件 进入vi全屏幕编辑画面 按字母i进入[输入模式],按[ESC]转到命令行, 输入 :q可不保存退出vi :wq存盘退出vi :q!不存盘强制退出 :w ...
- HTML与CSS入门——第五章 使用文本块和列表
知识点: 1.在页面上对齐文本的方法 2.三种HTML列表的使用方法 3.在列表中放置列表的方法 5.1 在页面上对齐文本: 父元素内子元素文本的居中:在控制父元素的text-align:center ...
- centos上如何安装mysql
centos可以使用yum安装mysql 但是版本很低,且不灵活. 本文将介绍如何使用安装包安装mysql http://dev.mysql.com/downloads/mysql/ 下载mysql ...
- 12 hdfs常用文件、目录拷贝操作、删除操作
package com.da.hbase.tool.utils; import com.da.hbase.tool.common.Const; import org.apache.hadoop.con ...
- POJ1995 Raising Modulo Numbers(快速幂)
POJ1995 Raising Modulo Numbers 计算(A1B1+A2B2+ ... +AHBH)mod M. 快速幂,套模板 /* * Created: 2016年03月30日 23时0 ...
- mac版sublime text2包管理器安装步骤
第一步: control+-打开命令执行窗口. 第二步: 将包管理器的代码复制到命令执行窗口: import urllib2,os,hashlib; h = '2915d1851351e5ee549c ...
- Pyzo -- 好用的 Python 轻量级 IDE
近期 yvivid 使用 Python 进行科学计算类应用(如matlab部分应用场景) 比较好的 发行版本为 Anaconda: A free distribution for the SciPy ...
- C语言初学 if-else语句判别在ASCII值中小于32的可控制符的类型
#include<stdio.h> main() { char c; printf("输入一个符号\n"); c=getchar(); if(c<32) prin ...