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

WPF:值转换器放在哪里?

starIconstarIconstarIconstarIconstarIcon

5.00/5 (22投票s)

2010年1月31日

Ms-PL

2分钟阅读

viewsIcon

39794

本文试图解决的问题是:值转换器放在哪里?

以下技巧并非新鲜事物;它基于这篇文章及其评论。但是,为了完整性和便于将来参考,我把最终版本放在这里。

本文试图解决的问题是:值转换器放在哪里?

常规方案

通常,放置值转换器的常用位置是在资源部分。有了这个,你可以使用 `StaticResource` 语法来使用值转换器。

<UserControl.Resources>
    <local:NotConverter x:Key="notConverter" />
</UserControl.Resources>

...

<StackPanel>
    <Button IsEnabled="{Binding Converter={StaticResource notConverter}}" />
</StackPanel>

这意味着每次你想使用值转换器时,都需要将其添加到资源部分。更好的方法是将其放在全局转换器资源文件中,这样资源定义只需进行一次。

巧妙方案

简而言之,让你的转换器继承自 `MarkupExtension`。这将完全避免这个问题。完整的解决方案提供了一个你应该从中继承的通用基类,`ConverterMarkupExtension`。从这个类继承的优点是:

  • 你的转换器可以用作标记扩展。因此,之前的代码变成了:
    <StackPanel>
        <Button IsEnabled="{Binding Converter={local:notConverter}}" />
    </StackPanel>

    具体来说,不需要任何资源定义。完全不需要。

  • 只使用你的转换器的一个实例来提供值(类似单例)。

    请注意,每次 XAML 编译器看到一个标记扩展时,它都会创建一个新实例,但是下面的实现总是返回相同的单个转换器。如果你担心标记扩展的所有短暂实例,只需考虑使用 `StaticResource`(另一个标记扩展)也会创建它们。因此,内存消耗没有额外的压力。

  • 基类为 `IValueConverter` 和 `IMultiValueConverter` 方法提供了默认实现。它抛出 `NotImplementedException`。这看起来似乎意义不大,但在你只实现一个转换方向的常见情况下,这有助于缩短你的转换器代码。

ConverterMarkupExtension,为清晰起见简短版本

public abstract class ConverterMarkupExtension<T> : MarkupExtension, IValueConverter,
    IMultiValueConverter
        where T : class, new()
    {
        private static T _converter = null; 

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (_converter == null)
            {
                _converter = new T();
            }

            return _converter;
        }

        #region IValueConverter Members

        public virtual object Convert(object value, Type targetType, object parameter,
            CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public virtual object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IMultiValueConverter Members
        ...
        
        #endregion

这里,你可以获得包含大量注释的完整代码版本。

使用基类

以下是使用 `ConverterMarkupExtension` 实现你自己的转换器的示例。

using System;
using System.Windows.Data;
using System.Globalization;

namespace WPF.Common
{
    /// <summary>
    /// Returns the negation of the given boolean value
    /// </summary>
    public class NotConverter : ConverterMarkupExtension<NotConverter>
    {
        public override object Convert(object value, Type targetType, object parameter,
            CultureInfo culture)
        {
            return !(bool)value;
        }
    }
}

请注意,值转换器代码实际上保持不变,但你可以将其用作标记扩展并删除“未实现”部分。

暂时就到这里,
Arik Poznanski。

© . All rights reserved.