博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一种用XAML写Data Converter的方式
阅读量:4837 次
发布时间:2019-06-11

本文共 8312 字,大约阅读时间需要 27 分钟。

在WPF程序中,数据绑定是非常常用的手段。伴随着数据绑定,我们通常还需要编写一些。而编写Converter是一件非常枯燥的事情,并且大量的converter不容易组织和维护。

今天在网上发现了一篇文章,它可以通过XAML的方式编写一些类似switch-case方式的converter,十分简洁明了。例如,对如如下的数据绑定转换:

    

可以直接在XAML中通过如下方式写converter:

原文已经附上了代码的工程,但由于担心哪天方校长抖威风而导致该文章失效,这里将其转录了下来,一共三个文件:

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{    ///     /// An individual case in the switch statement.    ///     [ContentProperty( "Then" )]    public sealed class SwitchCase : DependencyObject    {        #region Constructors        ///         /// Initializes a new instance of the 
class. ///
public SwitchCase( ) { } #endregion #region Properties /// /// Dependency property for the
property. ///
public static readonly DependencyProperty WhenProperty = DependencyProperty.Register( "When", typeof( object ), typeof( SwitchCase ), new PropertyMetadata( default( object ) ) ); /// /// The value to match against the input value. /// public object When { get { return (object)GetValue( WhenProperty ); } set { SetValue( WhenProperty, value ); } } /// /// Dependency property for the
property. ///
public static readonly DependencyProperty ThenProperty = DependencyProperty.Register( "Then", typeof( object ), typeof( SwitchCase ), new PropertyMetadata( default( object ) ) ); /// /// The output value to use if the current case matches. /// 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{    ///     /// A collection of switch cases.    ///     public sealed class SwitchCaseCollection : Collection
{ #region Constructors ///
/// Initializes a new instance of the
class. ///
internal SwitchCaseCollection( ) { } #endregion #region Methods ///
/// Adds a new case to the collection. /// ///
The value to compare against the input. ///
The output value to use if the case matches. 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{    ///     /// Produces an output value based upon a collection of case statements.    ///     [ContentProperty( "Cases" )]    public class SwitchConverter : IValueConverter    {        #region Constructors        ///         /// Initializes a new instance of the 
class. ///
public SwitchConverter( ) : this( new SwitchCaseCollection( ) ) { } /// /// Initializes a new instance of the
class. ///
/// The case collection. internal SwitchConverter( SwitchCaseCollection cases ) { Contract.Requires( cases != null ); Cases = cases; StringComparison = StringComparison.OrdinalIgnoreCase; } #endregion #region Properties /// /// Holds a collection of switch cases that determine which output /// value will be produced for a given input value. /// public SwitchCaseCollection Cases { get; private set; } /// /// Specifies the type of comparison performed when comparing the input /// value against a case. /// public StringComparison StringComparison { get; set; } /// /// An optional value that will be output if none of the cases match. /// public object Else { get; set; } #endregion #region Methods /// /// Converts a value. /// /// The value produced by the binding source. /// The type of the binding target property. /// The converter parameter to use. /// The culture to use in the converter. ///
A converted value. If the method returns null, the valid null value is used.
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; } /// /// Converts a value. /// /// The value that is produced by the binding target. /// The type to convert to. /// The converter parameter to use. /// The culture to use in the converter. ///
A converted value. If the method returns null, the valid null value is used.
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) { throw new NotSupportedException( ); } /// /// Attempts to use the IConvertible interface to convert
into a type /// compatible with
. ///
/// The culture. /// The input value. /// The case value. ///
True if conversion was performed, otherwise false.
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。例如:。在自己编写Converter之前,不妨先使用这些通用的Converter。

转载于:https://www.cnblogs.com/TianFang/p/3238996.html

你可能感兴趣的文章
设计模式——单例模式 (C++实现)
查看>>
UML和模式应用学习笔记(6)——系统顺序图、系统操作和层
查看>>
Android -- startActivityForResult和setResult
查看>>
1019 General Palindromic Number (20 分)
查看>>
关于c语言中指针的一些理解
查看>>
Expm 2_2 查找中项问题
查看>>
启动与关闭hadoop
查看>>
7.2 Move Field(搬移字段)
查看>>
[置顶] C#执行Excel宏模版的方法
查看>>
2015年9月28日JQuery提前预习预热笔记
查看>>
perl 删除过期文件
查看>>
document.write与document.getElementById的区别
查看>>
搜索可用docker镜像
查看>>
python基础知识梳理-----7函数
查看>>
函数极限的定义
查看>>
POJ 3684 Priest John's Busiest Day 2-SAT+输出路径
查看>>
oracle10g、oracle client和plsql devement 三者之间的关系
查看>>
ICDM评选:数据挖掘十大经典算法
查看>>
巧用「打印」功能实现PDF单页提取
查看>>
【转】Mongo初体验
查看>>