在 XAML 中对非绑定数据使用 IValueConverter

Using an IValueConverter on non bound data in XAML

我写了一个 IValueConverter 来处理 WPF 元素中的本地化和翻译;

public class LanguageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return string.Empty;

        if (value is string)
            return LocalizedStrings.Retreive((string)value);
        else
            return string.Empty;
    }

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

但我也想在非绑定数据中使用它,即将已知字符串发送到转换器而不是来自元素数据上下文的 属性。我该怎么做?

我想我应该澄清一下,我的目的是在 XAML 中为 UI 使用它,如果它也有设计时支持会很有帮助。

我确实尝试过使用 ConverterParameter 来提供源字符串的变体,但在设计时我的所有文本都被替换为 System.Object 文本,所以不是很有用。

还希望尽可能避免创建重载或继承的用户控件。

But I also want to use it in non bound data aswell, ie send a known string into the converter rather than a property from the elements data context. How can I go about that?

您实际上不能这样做,因为仅当解析到源 属性 的绑定以及更新源 属性 时,才会调用 Converter 的 Convert 方法。如果绑定到源 属性 失败,例如,当您在 XAML 标记中定义了无效的绑定路径,或者根本没有要绑定的 DataContext 时,您的 Convert 方法将不会被调用.

并且当根本没有应用到目标的绑定时 属性,转换器也不会被调用。

所以你必须始终确保确实有一个 属性 可以绑定到它才能工作。也许你可以绑定到虚拟 属性 或其他东西。

您可以创建一个 MarkupExtensionstring 作为参数并在 ProvideValue 覆盖中调用您的转换器。这是一个示例实现:

public class TranslateExtension : MarkupExtension
{
    public TranslateExtension(string text)
    {
        Text = text;
    }

    private static readonly LanguageConverter _converter = new LanguageConverter();

    public string Text { get; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return _converter.Convert(Text, null, null, null);
    }
}

然后您可以像这样在 XAML 中使用它:

<TextBlock Text="{local:Translate 'text to translate'}" />

请注意,更改语言需要 XAML 变为 re-read,因为 ProvideValue 方法仅在实现您的 XAML 定义时调用一次。如果你想要一个动态的方法,你可以参考 答案。