一种用XAML写Data Converter的方式
在WPF程序中,数据绑定是非常常用的手段。伴随着数据绑定,我们通常还需要编写一些Converter。而编写Converter是一件非常枯燥的事情,并且大量的converter不容易组织和维护。
今天在网上发现了一篇文章SwitchConverter – A "switch statement" for XAML,它可以通过XAML的方式编写一些类似switch-case方式的converter,十分简洁明了。例如,对如如下的数据绑定转换:
可以直接在XAML中通过如下方式写converter:
<Grid><Grid.Resources><e:SwitchConverter x:Key="WeatherIcons"><e:SwitchCase When="Sunny" Then="Sunny.png" /><e:SwitchCase When="Cloudy" Then="Cloudy.png" /><e:SwitchCase When="Rain" Then="Rain.png" /><e:SwitchCase When="Snow" Then="Snow.png" /></e:SwitchConverter></Grid.Resources><Image Source="{Binding Condition, Converter={StaticResource WeatherIcons}}" /> </Grid>
原文已经附上了代码的工程,但由于担心哪天方校长抖威风而导致该文章失效,这里将其转录了下来,一共三个文件:
SwitchCase.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.Contracts; using System.Linq; using System.Windows; using System.Windows.Markup;namespace SwitchConverterDemo {/// <summary>/// An individual case in the switch statement./// </summary>[ContentProperty( "Then" )]public sealed class SwitchCase : DependencyObject{#region Constructors/// <summary>/// Initializes a new instance of the <see cref="T:SwitchCase"/> class./// </summary>public SwitchCase( ){}#endregion#region Properties/// <summary>/// Dependency property for the <see cref="P:When"/> property./// </summary>public static readonly DependencyProperty WhenProperty = DependencyProperty.Register( "When", typeof( object ), typeof( SwitchCase ), new PropertyMetadata( default( object ) ) );/// <summary>/// The value to match against the input value./// </summary>public object When{get{return (object)GetValue( WhenProperty );}set{SetValue( WhenProperty, value );}}/// <summary>/// Dependency property for the <see cref="P:Then"/> property./// </summary>public static readonly DependencyProperty ThenProperty = DependencyProperty.Register( "Then", typeof( object ), typeof( SwitchCase ), new PropertyMetadata( default( object ) ) );/// <summary>/// The output value to use if the current case matches./// </summary>public object Then{get{return (object)GetValue( ThenProperty );}set{SetValue( ThenProperty, value );}}#endregion} // class } // namespace
View Code
SwitchCaseCollection.cs
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics.Contracts; using System.Linq;namespace SwitchConverterDemo {/// <summary>/// A collection of switch cases./// </summary>public sealed class SwitchCaseCollection : Collection<SwitchCase>{#region Constructors/// <summary>/// Initializes a new instance of the <see cref="T:SwitchCaseCollection"/> class./// </summary>internal SwitchCaseCollection( ){}#endregion#region Methods/// <summary>/// Adds a new case to the collection./// </summary>/// <param name="when">The value to compare against the input.</param>/// <param name="then">The output value to use if the case matches.</param>public void Add( object when, object then ){Add(new SwitchCase {When = when,Then = then});}#endregion} // class } // namespace
View Code
SwitchConverter.cs
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Data; using System.Windows.Markup;namespace SwitchConverterDemo {/// <summary>/// Produces an output value based upon a collection of case statements./// </summary>[ContentProperty( "Cases" )]public class SwitchConverter : IValueConverter{#region Constructors/// <summary>/// Initializes a new instance of the <see cref="T:SwitchConverter"/> class./// </summary>public SwitchConverter( ): this( new SwitchCaseCollection( ) ){}/// <summary>/// Initializes a new instance of the <see cref="T:SwitchConverter"/> class./// </summary>/// <param name="cases">The case collection.</param>internal SwitchConverter( SwitchCaseCollection cases ){Contract.Requires( cases != null );Cases = cases;StringComparison = StringComparison.OrdinalIgnoreCase;}#endregion#region Properties/// <summary>/// Holds a collection of switch cases that determine which output/// value will be produced for a given input value./// </summary>public SwitchCaseCollection Cases{get;private set;}/// <summary>/// Specifies the type of comparison performed when comparing the input/// value against a case./// </summary>public StringComparison StringComparison{get;set;}/// <summary>/// An optional value that will be output if none of the cases match./// </summary>public object Else{get;set;}#endregion#region Methods/// <summary>/// Converts a value./// </summary>/// <param name="value">The value produced by the binding source.</param>/// <param name="targetType">The type of the binding target property.</param>/// <param name="parameter">The converter parameter to use.</param>/// <param name="culture">The culture to use in the converter.</param>/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>public object Convert( object value, Type targetType, object parameter, CultureInfo culture ){if ( value == null ) {// Special case for null// Null input can only equal null, no convert necessaryreturn Cases.FirstOrDefault( x => x.When == null ) ?? Else;}foreach ( var c in Cases.Where( x => x.When != null ) ) {// Special case for string to string comparisonif ( value is string && c.When is string ) {if ( String.Equals( (string)value, (string)c.When, StringComparison ) ) {return c.Then;}}object when = c.When;// Normalize the types using IConvertible if possibleif ( TryConvert( culture, value, ref when ) ) {if ( value.Equals( when ) ) {return c.Then;}}}return Else;}/// <summary>/// Converts a value./// </summary>/// <param name="value">The value that is produced by the binding target.</param>/// <param name="targetType">The type to convert to.</param>/// <param name="parameter">The converter parameter to use.</param>/// <param name="culture">The culture to use in the converter.</param>/// <returns>A converted value. If the method returns null, the valid null value is used.</returns>public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ){throw new NotSupportedException( );}/// <summary>/// Attempts to use the IConvertible interface to convert <paramref name="value2"/> into a type/// compatible with <paramref name="value1"/>./// </summary>/// <param name="culture">The culture.</param>/// <param name="value1">The input value.</param>/// <param name="value2">The case value.</param>/// <returns>True if conversion was performed, otherwise false.</returns>private static bool TryConvert( CultureInfo culture, object value1, ref object value2 ){Type type1 = value1.GetType( );Type type2 = value2.GetType( );if ( type1 == type2 ) {return true;}if ( type1.IsEnum ) {value2 = Enum.Parse( type1, value2.ToString( ), true );return true;}var convertible1 = value1 as IConvertible;var convertible2 = value2 as IConvertible;if ( convertible1 != null && convertible2 != null ) {value2 = System.Convert.ChangeType( value2, type1, culture );return true;}return false;}#endregion} // class } // namespace
View Code
这种绑定的方式非常简洁有效,但也有限制,只能处理简单的switch-case形式的关联,并且不能有转换逻辑。不过已经可以替换很大一部分Converter了(非常典型的应用就是这种枚举到图片的转换)。
另外,网上也有一些开源库,实现了一些常见的通用Converter。例如:http://wpfconverters.codeplex.com/。在自己编写Converter之前,不妨先使用这些通用的Converter。
一种用XAML写Data Converter的方式相关推荐
- 一种用markdown写PPT的方法,再也不用费劲排版了
前言 本文源代码位于:https://github.com/pzqu/tools 原创首发:https://coding3min.com/1134.html 今天看jeremyxu 的技术点滴,发现分 ...
- 课程设计代写java,JAVA课程设计作业代做、代写JAVA编程设计作业、代写data留学生作业...
JAVA课程设计作业代做.代写JAVA编程设计作业.代写data留学生作业 日期:2020-06-13 11:30 JAVA Coursework (30 marks) Suppose you nee ...
- Redis入门总结(一):redis配置文件,五种数据结构,线程模型和持久化方式
(尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.csdn.net/article/details/90321396冷血之心的博客) 关注微信公众号(文强的技术小屋) ...
- unity3d 自动变化大小_一种可扩展的Unity3d资源检查方式
unity3d的资源使用是一件十分费心的事,通常都需要自动化的手段来检查与处理资源,以保证游戏性能不会因资源规格的变化出现剧烈波动. 一般来说贴图.模型.动作.特效.prefab是最常见的几种需要按规 ...
- OpenCV学习笔记(二):3种常用访问图像中像素的方式
OpenCV学习笔记(二):3种常用访问图像中像素的方式 #include <opencv2/opencv.hpp>using namespace cv; using namespace ...
- java乘法表_Java中四种9*9乘法表的实现方式(附代码)
前言: 初学java,实现99乘法表是必学必会的内容. 需求 : 分别写出上下左右,对应四个角的乘法表. 思路: 可以先打印出*星星,形成一个直角三角形,然后再替换成乘法公式. 代码如下: publi ...
- vue 给取data值_vue获取data值的方式分析
上一篇文章我们简单讲解了data初始化的两种方式,这次我们分析一下获取data内值的方式 获取vue的data 我们常用获取data值的方式为如下两种: this.$data.link this.li ...
- 网络虚拟化有几种实现方式_介绍几种网络营销的免费渠道推广方式
介绍几种网络营销的免费渠道推广方式是由B2B101网站(http://www.b2b101.com)为您收集修改整理而来,更多相关内容请关注B2B101网站b2b营销推广栏目. 现在越来越多的传统企业 ...
- 03-编写dao实现类方式
目录 一.实现类 1.代码 2.解释 3.注意 一.实现类 1.代码 package dao.impl;import dao.IUserDao; import domain.User; import ...
最新文章
- mysql免安装版的问题
- DataWorks数据建模公开课上线啦!
- 基于ABP落地领域驱动设计-05.实体创建和更新最佳实践
- leetcode--Rotate List
- Google 加入反 IE6 联盟:IE6 真的能被消灭吗?
- 上位机开发实用语言软件分析
- 动作捕捉用于蛇运动分析及蛇形机器人开发
- git push报错: Push rejected
- Emacs指北(做一个搬运工好累)
- SEC主席Gary Gensler在被问及以太坊是否是证券时,选择了沉默
- Unity3D Editor 编辑器扩展3 Editor脚本
- 【Qt学习笔记】包含头文件确报错 does not name a type
- 转载自www.dezai.cn 常用sql统计
- springMVC + Dubbo + zooKeeper超详细 步骤
- 全球与中国便携式USB摄像机市场现状及未来发展趋势(2022)
- Web实验六 JavaScript实验
- 音视频编辑合成,配音合成视频。
- win xp 70技巧 不求人
- 干货 | 什么是FOC?一文带你看BLDC电机驱动芯片及解决方案
- 使用shiro进行系统身份验证-权限控制,登录界面乱跳