一种用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
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的方式的更多相关文章
- WPF的DataGrid的某个列绑定数据的三种方法(Binding、Converter、DataTrigger)
最近在使用WPF的时候,遇到某个列的值需要根据内容不同进行转换显示的需求.尝试了一下,大概有三种方式可以实现: 1.传统的Binding方法,后台构造好数据,绑定就行. 2.转换器方法(Convert ...
- Xaml引用图片路径的方式
最近写代码的时候遇到过好几次引用某个路径下图片资源的情况,思索了一下,便将自己所知的在xaml里引用图片资源的方法写成了个小Demo,并完成了这篇博文.希望罗列出的这些方式能够对大家有所帮助. Xam ...
- js replace 全局替换 以表单的方式提交参数 判断是否为ie浏览器 将jquery.qqFace.js表情转换成微信的字符码 手机端省市区联动 新字体引用本地运行可以获得,放到服务器上报404 C#提取html中的汉字 MVC几种找不到资源的解决方式 使用Windows服务定时去执行一个方法的三种方式
js replace 全局替换 js 的replace 默认替换只替换第一个匹配的字符,如果字符串有超过两个以上的对应字符就无法进行替换,这时候就要进行一点操作,进行全部替换. <scrip ...
- Java中几种office文档转pdf的方式
最近公司要做office的文档,搜集了几种office文档转pdf的方式,简单的做下总结 我主要尝试了三种方式:openoffice,aspose,jacob 对他们进行了大文件,小文件,在linux ...
- Android两种为ViewPager+Fragment添加Tab的方式
在Android开发中ViewPager的使用是非常广泛的,而它不仅仅能够实现简单的开始引导页,还可以结合Fragment并添加Tab作为选项卡或为显示大批量页面实现强大的顺畅滑动 下面介绍两种为Vi ...
- 简单总结几种常见web攻击手段及其防御方式
web攻击手段有几种,本文简单介绍几种常见的攻击手段及其防御方式 XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS XSS 概念 全称是跨站脚本攻击(Cross Site Scr ...
- 简单地总结几种常见web攻击手段及其防御方式
web攻击手段有几种,本文简单介绍几种常见的攻击手段及其防御方式 XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS XSS 概念 全称是跨站脚本攻击(Cross Site Scr ...
- jQuery.data() 的实现方式,jQuery16018518865841457738的由来,jQuery后边一串数字的由来
原文地址: http://xxing22657-yahoo-com-cn.iteye.com/blog/1042440 jQuery.data() 的实现方式 jQuery.data() 的作用是为普 ...
- 几种常见web攻击手段及其防御方式
XSS(跨站脚本攻击) CSRF(跨站请求伪造) SQL注入 DDOS web安全系列目录 总结几种常见web攻击手段极其防御方式 总结几种常见的安全算法 XSS 概念 全称是跨站脚本攻击(Cross ...
随机推荐
- 基于HTTP协议的轻量级开源简单队列服务:HTTPSQS[转]
HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key ...
- 【bzoj1195】[HNOI2006]最短母串 AC自动机+状态压缩+BFS最短路
原文地址:http://www.cnblogs.com/GXZlegend/p/6825226.html 题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串 ...
- SQL触发器(AFTER和INSTEAD OF)
转自:http://www.cnblogs.com/shepherldeng/archive/2010/06/23/1763766.html 何为触发器:触发器是数据库服务器中发生事件时自动执行的特种 ...
- Java基础复习--java.util.Timer定时任务
在java中,Timer类主要用于定时性.周期性任务 的触发,这个类中有两个方法比较难理解,那就是schedule和scheduleAtFixedRate方法,在这里就用实例分析一下. (1)sche ...
- 洛谷P3166 [CQOI2014]数三角形
题目描述 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个.下图为4x4的网格上的一个三角形.注意三角形的三点不能共线. 输入输出格式 输入格式: 输入一行,包含两个空格分隔的正整数m和n ...
- LNMP下安装phpmyadmin的一个小错误解决办法
环境:ubuntu16.04 + nginx1.10.0 + php7.04 + mysql5.6 安装phpmyadmin之后tail nginx 的错误日志,提示以下: 2016/06/30 15 ...
- [ CodeVS冲杯之路 ] P3115
不充钱,你怎么AC? 题目:http://codevs.cn/problem/3115/ 基础的高精度减法,先判断一下被减数是否小于减数,若是则交换位置,打上 “-” 负号 当然也可以用压位做 #in ...
- Linux Mint---安装docky
这个安装的时候没啥难度,直接在软件中心安装一下就可以了,效果很赞的,linux下最棒的dock, 简洁大方,效果好! 只不有过一点需要注意,这个东东直接很上拖是添加不上去的 需要从/usr/share ...
- bind 简单配置dns
一. 安装apt-get install bind9 apt-get install bind9-host dnsutils apt-get install bind9-doc 二.修改本机配置我们要 ...
- 自己写操作系统 2 - 安装bochs虚拟机
以ubuntu操作系统为例 一.命令行安装 sudo apt-get install vgabios bochs bochs-x bximage 此方法方便,不过都说这个方法安装的bochs没有调试功 ...