在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的方式相关推荐

  1. 一种用markdown写PPT的方法,再也不用费劲排版了

    前言 本文源代码位于:https://github.com/pzqu/tools 原创首发:https://coding3min.com/1134.html 今天看jeremyxu 的技术点滴,发现分 ...

  2. 课程设计代写java,JAVA课程设计作业代做、代写JAVA编程设计作业、代写data留学生作业...

    JAVA课程设计作业代做.代写JAVA编程设计作业.代写data留学生作业 日期:2020-06-13 11:30 JAVA Coursework (30 marks) Suppose you nee ...

  3. Redis入门总结(一):redis配置文件,五种数据结构,线程模型和持久化方式

    (尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.csdn.net/article/details/90321396冷血之心的博客) 关注微信公众号(文强的技术小屋) ...

  4. unity3d 自动变化大小_一种可扩展的Unity3d资源检查方式

    unity3d的资源使用是一件十分费心的事,通常都需要自动化的手段来检查与处理资源,以保证游戏性能不会因资源规格的变化出现剧烈波动. 一般来说贴图.模型.动作.特效.prefab是最常见的几种需要按规 ...

  5. OpenCV学习笔记(二):3种常用访问图像中像素的方式

    OpenCV学习笔记(二):3种常用访问图像中像素的方式 #include <opencv2/opencv.hpp>using namespace cv; using namespace ...

  6. java乘法表_Java中四种9*9乘法表的实现方式(附代码)

    前言: 初学java,实现99乘法表是必学必会的内容. 需求 : 分别写出上下左右,对应四个角的乘法表. 思路: 可以先打印出*星星,形成一个直角三角形,然后再替换成乘法公式. 代码如下: publi ...

  7. vue 给取data值_vue获取data值的方式分析

    上一篇文章我们简单讲解了data初始化的两种方式,这次我们分析一下获取data内值的方式 获取vue的data 我们常用获取data值的方式为如下两种: this.$data.link this.li ...

  8. 网络虚拟化有几种实现方式_介绍几种网络营销的免费渠道推广方式

    介绍几种网络营销的免费渠道推广方式是由B2B101网站(http://www.b2b101.com)为您收集修改整理而来,更多相关内容请关注B2B101网站b2b营销推广栏目. 现在越来越多的传统企业 ...

  9. 03-编写dao实现类方式

    目录 一.实现类 1.代码 2.解释 3.注意 一.实现类 1.代码 package dao.impl;import dao.IUserDao; import domain.User; import ...

最新文章

  1. mysql免安装版的问题
  2. DataWorks数据建模公开课上线啦!
  3. 基于ABP落地领域驱动设计-05.实体创建和更新最佳实践
  4. leetcode--Rotate List
  5. Google 加入反 IE6 联盟:IE6 真的能被消灭吗?
  6. 上位机开发实用语言软件分析
  7. 动作捕捉用于蛇运动分析及蛇形机器人开发
  8. git push报错: Push rejected
  9. Emacs指北(做一个搬运工好累)
  10. SEC主席Gary Gensler在被问及以太坊是否是证券时,选择了沉默
  11. Unity3D Editor 编辑器扩展3 Editor脚本
  12. 【Qt学习笔记】包含头文件确报错 does not name a type
  13. 转载自www.dezai.cn 常用sql统计
  14. springMVC + Dubbo + zooKeeper超详细 步骤
  15. 全球与中国便携式USB摄像机市场现状及未来发展趋势(2022)
  16. Web实验六 JavaScript实验
  17. 音视频编辑合成,配音合成视频。
  18. win xp 70技巧 不求人
  19. 干货 | 什么是FOC?一文带你看BLDC电机驱动芯片及解决方案
  20. 使用shiro进行系统身份验证-权限控制,登录界面乱跳

热门文章

  1. 业务脆弱性评估是业务持续性保障(BCM)的基础数据
  2. Windows 7 下如何调整网卡的优先级
  3. Emm,qW3xT.2(矿机进程)
  4. C语言函数指针的使用
  5. Android更新带进度条的通知栏
  6. Broadcast Receiver广播接收器
  7. ewebeditor下利用ckplayer增加html5 (mp4)全平台的支持
  8. Erlang 数据类型。。
  9. 解决naigos+pnp4nagios部分不出图的问题
  10. Linux项目零散笔记