本文介绍了如何使数据绑定类型安全并支持重构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 当我希望将控件绑定到对象的属性时,我必须以属性的形式提供字符串的名称。这不是很好,因为: 如果属性被删除或重命名,我没有得到一个编译器警告。 如果使用重构工具重命名财产,则可能会更新。 如果财产的类型错误,我直到运行时才会收到错误,例如将一个整数绑定到a日期选择器。 有没有一个设计模式,使用数据绑定? (这是WinForm,Asp.net和WPF中的一个问题,很可能是很多其他系统) 我现在发现名称的解决方法()运算符在C#:typesafe数据绑定,这也是解决方案的一个很好的起点。 如果您愿意在编译后使用后处理器您的代码, notifypropertyweaver 非常值得一看。 当绑定在XML而不是C#中完成时,任何人都知道一个很好的解决方案。解决方案感谢Oliver让我开始,我现在有了一个解决方案支持重构,类型安全。它也让我实现INotifyPropertyChanged,以便处理重命名的属性。 它的用法如下: checkBoxCanEdit.Bind(c => c.Checked,person,p => p.UserCanEdit); textBoxName.BindEnabled(person,p => p.UserCanEdit); checkBoxEmployed.BindEnabled(person,p => p.UserCanEdit); trackBarAge.BindEnabled(person,p => p.UserCanEdit); textBoxName.Bind(c => c.Text,person,d => d.Name); checkBoxEmployed.Bind(c => c.Checked,person,d => d.Employed); trackBarAge.Bind(c => c.Value,person,d => d.Age); labelName.BindLabelText(person,p => p.Name); labelEmployed.BindLabelText(person,p => p.Employed); labelAge.BindLabelText(person,p => p.Age); 该人员课程显示了如何以类型安全的方式实现INotifyPropertyChanged(或看到这个答案,用于实现INotifyPropertyChanged, ActiveSharp - 自动INotifyPropertyChanged 也看起来不错): public class Person :INotifyPropertyChanged { private bool _employed; public bool雇用 { get {return _employed; } set { _employed = value; OnPropertyChanged(()=> c.Employed); } } // etc private void OnPropertyChanged(表达式< Func< object>>属性) { if(PropertyChanged!= null) { PropertyChanged(this, new PropertyChangedEventArgs(BindingHelper.Name(property))); } } public event PropertyChangedEventHandler PropertyChanged; } WinForms绑定帮助器类中的内容使其全部工作: 命名空间TypeSafeBinding { public static class BindingHelper { private static字符串GetMemberName(表达式表达式) { //名称操作符是在2015年7月的.NET 4.6 //和VS2015的C#6.0中实现的。 //以下是仍然适用于C# 6.0 switch(expression.NodeType) { case ExpressionType.MemberAccess: var memberExpression =(MemberExpression)expression; var supername = GetMemberName(memberExpression.Expression); if(String.IsNullOrEmpty(supername))return memberExpression.Member.Name; return String.Concat(supername,'。',memberExpression.Member.Name); case ExpressionType.Call: var callExpression =(MethodCallExpression)expression; return callExpression.Method.Name; case ExpressionType.Convert: var unaryExpression =(UnaryExpression)expression; return GetMemberName(unaryExpression.Operand); case ExpressionType.Parameter: case ExpressionType.Constant://更改 return String.Empty; default: throw new ArgumentException(表达式不是成员访问或方法调用表达式); } } public static string Name< T,T2>(Expression< Func< T,T2>>表达式) { return GetMemberName(expression.Body); } // NEW public static string Name< T>(Expression< Func< T>>表达式) { return GetMemberName表达。 } public static void Bind { control.DataBindings.Add(Name(controlProperty),dataSource,Name(dataMember)); } public static void BindLabelText< T>(此Label控件,T dataObject,Expression&FunC< T,object>> dataMember) { / /因为这是一种任何类型的属性是ok control.DataBindings.Add(Text,dataObject,Name(dataMember)); } public static void BindEnabled< T>(此控件控件,T dataObject,Expression< Func< T,bool>> dataMember) {控件.Bind(c => c.Enabled,dataObject,dataMember); } } } 这使得很多的C#3.5中的新东西,并显示出什么是可能的。现在如果只有我们有卫生宏,lisp程序员可能会停止给我们打电话给二等公民) When I wish to bind a control to a property of my object, I have to provide the name of the property as a string. This is not very good because:If the property is removed orrenamed, I don’t get a compilerwarning.If a rename the propertywith a refactoring tool, it islikely the data binding will not beupdated.I don’t get an error untilruntime if the type of the propertyis wrong, e.g. binding an integer toa date chooser.Is there a design-pattern that gets round this, but still has the ease of use of data-binding?(This is a problem in WinForm, Asp.net and WPF and most likely lots of other systems)I have now found "workarounds for nameof() operator in C#: typesafe databinding" that also has a good starting point for a solution.If you are willing to use a post processor after compiling your code, notifypropertyweaver is well worth looking at.Anyone knows of a good solution for WPF when the bindings are done in XML rather then C#? 解决方案 Thanks to Oliver for getting me started I now have a solution that both supports refactoring and is type safe. It also let me implement INotifyPropertyChanged so it copes with properties being renamed.It’s usage looks like:checkBoxCanEdit.Bind(c => c.Checked, person, p => p.UserCanEdit);textBoxName.BindEnabled(person, p => p.UserCanEdit);checkBoxEmployed.BindEnabled(person, p => p.UserCanEdit);trackBarAge.BindEnabled(person, p => p.UserCanEdit);textBoxName.Bind(c => c.Text, person, d => d.Name);checkBoxEmployed.Bind(c => c.Checked, person, d => d.Employed);trackBarAge.Bind(c => c.Value, person, d => d.Age);labelName.BindLabelText(person, p => p.Name);labelEmployed.BindLabelText(person, p => p.Employed);labelAge.BindLabelText(person, p => p.Age);The person class shows how to implemented INotifyPropertyChanged in a type safe way (or see this answer for a other rather nice way of implementing INotifyPropertyChanged, ActiveSharp - Automatic INotifyPropertyChanged also looks good ): public class Person : INotifyPropertyChanged{ private bool _employed; public bool Employed { get { return _employed; } set { _employed = value; OnPropertyChanged(() => c.Employed); } } // etc private void OnPropertyChanged(Expression<Func<object>> property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(BindingHelper.Name(property))); } } public event PropertyChangedEventHandler PropertyChanged;}The WinForms binding helper class has the meat in it that makes it all work:namespace TypeSafeBinding{ public static class BindingHelper { private static string GetMemberName(Expression expression) { // The nameof operator was implemented in C# 6.0 with .NET 4.6 // and VS2015 in July 2015. // The following is still valid for C# < 6.0 switch (expression.NodeType) { case ExpressionType.MemberAccess: var memberExpression = (MemberExpression) expression; var supername = GetMemberName(memberExpression.Expression); if (String.IsNullOrEmpty(supername)) return memberExpression.Member.Name; return String.Concat(supername, '.', memberExpression.Member.Name); case ExpressionType.Call: var callExpression = (MethodCallExpression) expression; return callExpression.Method.Name; case ExpressionType.Convert: var unaryExpression = (UnaryExpression) expression; return GetMemberName(unaryExpression.Operand); case ExpressionType.Parameter: case ExpressionType.Constant: //Change return String.Empty; default: throw new ArgumentException("The expression is not a member access or method call expression"); } } public static string Name<T, T2>(Expression<Func<T, T2>> expression) { return GetMemberName(expression.Body); } //NEW public static string Name<T>(Expression<Func<T>> expression) { return GetMemberName(expression.Body); } public static void Bind<TC, TD, TP>(this TC control, Expression<Func<TC, TP>> controlProperty, TD dataSource, Expression<Func<TD, TP>> dataMember) where TC : Control { control.DataBindings.Add(Name(controlProperty), dataSource, Name(dataMember)); } public static void BindLabelText<T>(this Label control, T dataObject, Expression<Func<T, object>> dataMember) { // as this is way one any type of property is ok control.DataBindings.Add("Text", dataObject, Name(dataMember)); } public static void BindEnabled<T>(this Control control, T dataObject, Expression<Func<T, bool>> dataMember) { control.Bind(c => c.Enabled, dataObject, dataMember); } }}This makes use of a lot of the new stuff in C# 3.5 and shows just what is possible. Now if only we had hygienic macros lisp programmer may stop calling us second class citizens) 这篇关于如何使数据绑定类型安全并支持重构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-05 21:27