在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

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

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 necessary return Cases.FirstOrDefault( x => x.When == null ) ?? Else; } foreach ( var c in Cases.Where( x => x.When != null ) ) { // Special case for string to string comparison
if ( 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 possible
if ( 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

这种绑定的方式非常简洁有效,但也有限制,只能处理简单的switch-case形式的关联,并且不能有转换逻辑。不过已经可以替换很大一部分Converter了(非常典型的应用就是这种枚举到图片的转换)。

另外,网上也有一些开源库,实现了一些常见的通用Converter。例如:http://wpfconverters.codeplex.com/。在自己编写Converter之前,不妨先使用这些通用的Converter。

一种用XAML写Data Converter的方式的更多相关文章

  1. WPF的DataGrid的某个列绑定数据的三种方法(Binding、Converter、DataTrigger)

    最近在使用WPF的时候,遇到某个列的值需要根据内容不同进行转换显示的需求.尝试了一下,大概有三种方式可以实现: 1.传统的Binding方法,后台构造好数据,绑定就行. 2.转换器方法(Convert ...

  2. Xaml引用图片路径的方式

    最近写代码的时候遇到过好几次引用某个路径下图片资源的情况,思索了一下,便将自己所知的在xaml里引用图片资源的方法写成了个小Demo,并完成了这篇博文.希望罗列出的这些方式能够对大家有所帮助. Xam ...

  3. js replace 全局替换 以表单的方式提交参数 判断是否为ie浏览器 将jquery.qqFace.js表情转换成微信的字符码 手机端省市区联动 新字体引用本地运行可以获得,放到服务器上报404 C#提取html中的汉字 MVC几种找不到资源的解决方式 使用Windows服务定时去执行一个方法的三种方式

    js replace 全局替换   js 的replace 默认替换只替换第一个匹配的字符,如果字符串有超过两个以上的对应字符就无法进行替换,这时候就要进行一点操作,进行全部替换. <scrip ...

  4. Java中几种office文档转pdf的方式

    最近公司要做office的文档,搜集了几种office文档转pdf的方式,简单的做下总结 我主要尝试了三种方式:openoffice,aspose,jacob 对他们进行了大文件,小文件,在linux ...

  5. Android两种为ViewPager+Fragment添加Tab的方式

    在Android开发中ViewPager的使用是非常广泛的,而它不仅仅能够实现简单的开始引导页,还可以结合Fragment并添加Tab作为选项卡或为显示大批量页面实现强大的顺畅滑动 下面介绍两种为Vi ...

  6. 简单总结几种常见web攻击手段及其防御方式

    web攻击手段有几种,本文简单介绍几种常见的攻击手段及其防御方式 XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS XSS 概念 全称是跨站脚本攻击(Cross Site Scr ...

  7. 简单地总结几种常见web攻击手段及其防御方式

    web攻击手段有几种,本文简单介绍几种常见的攻击手段及其防御方式 XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS XSS 概念 全称是跨站脚本攻击(Cross Site Scr ...

  8. jQuery.data() 的实现方式,jQuery16018518865841457738的由来,jQuery后边一串数字的由来

    原文地址: http://xxing22657-yahoo-com-cn.iteye.com/blog/1042440 jQuery.data() 的实现方式 jQuery.data() 的作用是为普 ...

  9. 几种常见web攻击手段及其防御方式

    XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS web安全系列目录 总结几种常见web攻击手段极其防御方式 总结几种常见的安全算法 XSS 概念 全称是跨站脚本攻击(Cross ...

随机推荐

  1. DevExpress的GridControl控件设置自定义显示方法

    比如要显示性别为字符串,数据库中保存为数值(1:男,2:女,3:未知). 方法一: 点击控件上的"Run Designer"按钮,进入设计界面. 选择“Columns", ...

  2. 没有外网情况下linux安装mysql

    首先linux要使用局域网 环境要求:局域网,  windows系统,  linux系统,  mysql安装包mysql.tar.gz 注意:32位操作系统用32位安装包,64位系统用64位安装包,不 ...

  3. BOZJ 2045:疯狂的馒头(并查集)

    题目大意:有n个馒头排成一排,初始时颜色为0,进行m次染色,第i次将(i*p+q)mod n到(i*q+p)mod n的馒头全部染成颜色i,求最后所有馒头颜色.n<=10^6 m<=10^ ...

  4. margin-top影响父元素定位

    写样式时无意中发现margin-top会影响到父元素的定位,下面是示例: HTML代码: <div class="demo"> <div class=" ...

  5. NOIP2017赛前模拟11月2日总结

    分数爆炸的一天··但也学了很多 题目1:活动安排 给定n个活动的开始时间与结束时间··只有一个场地··要求保留尽量多的活动且时间不冲突···场地数n<=100000 考点:贪心 直接将结束时间按 ...

  6. eclipse增加jar包方式对比

    add external jars  = 增加工程外部的包add jars = 增加工程内包add library = 增加一个库add class folder = 增加一个类文件夹 add jar ...

  7. Ajax基础知识 浅析(含php基础语法知识)

    1.php基础语法    后缀名为.php的文件 (1) echo   向页面中输入字符串  <?php    所有php相关代码都要写在<?php ?>这个标签之中 echo &q ...

  8. pagination用法

    pagination用法: 1.html  要用两层div <script src="${app }/pc/js/media/pagination.js"></s ...

  9. hdu 5072 计数+容斥原理

    /* 题意: 给出n个数(n<100000), 每个数都不大于100000,数字不会有重复.现在随意抽出3个,问三个彼此互质 或者 三个彼此不互质的数目有多少. 思路: 这道题反着想,就是三个数 ...

  10. 百度之星复赛T6&&hd6149 ——Valley Numer II

    Problem Description 众所周知,度度熊非常喜欢图. 它最近发现了图中也是可以出现 valley —— 山谷的,像下面这张图. 为了形成山谷,首先要将一个图的顶点标记为高点或者低点.标 ...