65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WPF 中使用 MarkupExtension 和 Converter

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.08/5 (9投票s)

2009年4月14日

CPOL

2分钟阅读

viewsIcon

67214

downloadIcon

382

使用 MarkupExtension 优化 WPF 中的转换器

介绍 

软件需要用与存储值不同的值来表示显示组件。WPF 提供了 Converter (IValueConverter/IMultiValueConverter) 功能来轻松地进行这种转换。我们将看到如何使用 converter 以及使用 MarkupExtension 访问 converter 的最佳方式。

背景

Markup Extension 是 WPF 框架提供的用于扩展 XAML 的内置功能。Markup extension 定义在花括号 ({}) 内。
WPF 框架提供的几个内置扩展包括

  • BindingExtension
  • StaticResourceExtension
  • DynamicResourceExtension
  • RelativeSourceExtension
  • StaticExtension
  • TypeExtension

就像 Dependency property 或属性一样,我们在 XAML 中访问它时不需要写“extension”这个词。 

Using the Code

本文主要分为两部分,如下所示

  1. 在 WPF 中使用 Converter 
  2. 使用 MarkupExtension 来优化 Converter 的构建

注意: 以下示例仅用于演示该概念。

在 WPF 应用程序中使用 Converter

Converter 在 WPF 中用于将一种数据类型的值转换为另一种数据类型。或者用简单的话来说,Converter (继承自 IValueConverter 的类)接受一种格式的值并以另一种格式返回值。

 public class NumberToStringConverter : IValueConverter
    {

    }

为了访问这个 converter,我们在 XAML 中声明一个资源。例如,

<Window.Resources>        
    <local:NumberToStringConverter x:Key="numConverter"></local:NumberToStringConverter>
</Window.Resources>

然后,我们按如下方式在 Binding 中访问这个 converter : 

<TextBox x:Name="txtBox1">100</TextBox>
<TextBox Text="{Binding Path=Text,Converter=
		{StaticResource numConverter},ElementName=txtBox1}" >

这是一个演示 converter 用法的简单示例。如果我们在不同的 XAML 中需要 converter,我们需要在每个 XAML 中重复上述代码。

现在,如果你仔细观察,这是一种冗余编码。我们将最终得到 n 个 converter 实例。你不认为 converter 的作用是将一种类型的值转换为另一种类型的值吗?那么我们真的需要创建 n 个 converter 类的实例吗?

使用 MarkupExtension 和 Singleton 创建 Converter

我们可以利用 WPF 的内置功能来消除这种冗余。WPF 提供了 MarkupExtension 在 XAML 中访问您的自定义对象。WPF MarkupExtension 允许我们以一种优化方式编写转换器。让我们看看如何做。

在上述情况下,我们可以在 XAML 中访问转换器实例,而无需创建其资源实例。为了实现这一点,Converter 必须从 MarkupExtension 继承。
MarkupExtension 是 WPF 框架定义的 abstract 类。我们需要重写 ProvideValue 方法。ProvideValue 方法接受类型为 IServiceProvider (也是一个框架声明的接口)的变量。我们可以使用此方法返回 Converter 的单例实例,如下所示:

[MarkupExtensionReturnType(typeof(IValueConverter))]
public class NumberToStringConverterExtension: MarkupExtension, IValueConverter
{
    private static NumberToStringConverterExtension _converter;
     public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (_converter == null)
        {
            _converter = new NumberToStringConverterExtension();
        }
        return _converter;
    }
     #region IValueConverter Members
     public object Convert(object value, Type targetType, 
	object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
        {
            return Binding.DoNothing;
        }
        return GetString(value);
    }
     public object ConvertBack(object value, Type targetType, 
	object parameter, System.Globalization.CultureInfo culture)
    {
        if (value != null && !string.IsNullOrEmpty(value.ToString()))
        {
            return GetInt(value);
        }
        return 0;
    }
     #endregion
     private string GetString(object value)
    {
        //Some logic to convert int to string..
        return value.ToString();
    }
     private int GetInt(object value)
    {
       //Some logic to convert string to int..
       int val;
       int.TryParse(value.ToString(), out val);
       return val;
    } 
}

我们可以在 XAML 中按如下方式使用此单例实例

<TextBox x:Name="txtBox1">100        
<TextBox Text="{Binding Path=Text,Converter=
	{local:NumberToStringConverter},ElementName=txtBox1}">

注意:在上面的代码片段中,您可以看到 NumberToStringConverter 扩展对象是在没有编写 Extension 后缀的情况下访问的。

值得关注的点  

使用 MarkupExtension 继承转换器允许开发人员直接在 XAML 中访问 Converter ,而无需将其声明为资源。同样,由于 converter 用于通用活动,因此实例可以设置为单例,从而限制用户创建多个实例。

历史

  • 第一个版本 - 2009 年 4 月 14 日 - 解释了如何使用 MarkupExtension Converter 作为 WPF 扩展来访问
© . All rights reserved.