使用DataBinding值的MarkupExtension

时间:2013-02-06 19:25:36

标签: wpf data-binding markup-extensions

我正在尝试创建一个WPF MarkupExtension类,它从我的文本翻译类提供翻译文本。翻译的东西效果很好,但需要使用文本键进行静态方法调用以返回翻译的文本。像这样:

ImportLabel.Text = Translator.Translate("import files");
// will be "Dateien importieren" in de or "Import files" in en

它的特点是它接受计数值以提供更好的措辞。

ImportLabel.Text = Translator.Translate("import n files", FileCount);
// will be "Import 7 files" or "Import 1 file"

另一个例子:如果事情还需要4分钟,那么这个词只需要一分钟。如果文本键“minutes”被定义为任何数字的“Minuten”,而“minute”被定义为1,则以下方法调用将返回要使用的右词:

Translator.Translate("minutes", numberOfMinutes)
// will be "minute" if it's 1, and "minutes" for anything else

现在在WPF应用程序中,有很多XAML代码,其中包含大量文字文本。为了能够翻译它们而不必坚持,我需要一个标记扩展,我可以传递我的文本键,并将在运行时返回翻译的文本。这部分相当容易。创建一个继承自MarkupExtension的类,添加一个接受文本键作为参数的构造函数,将其存储在私有字段中,并让其ProvideValue方法返回存储键的翻译文本。

我真正的问题是:如何使我的标记扩展接受计数值,使其受数据限制,并且当计数值发生变化时,翻译文本将相应更新?

它应该像这样使用:

<TextBlock Text="{t:Translate 'import files', {Binding FileCount}}"/>

每当FileCount的绑定值发生更改时,TextBlock都必须接收新的文本值以反映更改,并仍然提供良好的措辞。

我在那里找到了一个类似的解决方案:http://blogs.microsoft.co.il/blogs/tomershamam/archive/2007/10/30/wpf-localization-on-the-fly-language-selection.aspx但是,尽管我努力遵循它,但我无法理解它的作用或为什么它会起作用。似乎所有事情都发生在WPF中,提供的代码只会将其推向正确的方向,但目前还不清楚如何。我不能让我适应它做任何有用的事情。

我不确定让翻译语言在运行时更改是否有用。我想我需要另一级别的绑定。为了保持低复杂性,我不会在基本版本工作之前这样做。

目前没有代码可以告诉你。它只是处于一种糟糕的状态,它唯一能做的就是抛出异常,或者不翻译任何东西。任何简单的例子都是非常受欢迎的(如果在这种情况下存在这样的事情)。

1 个答案:

答案 0 :(得分:15)

没关系,我终于找到了引用的代码是如何工作的,并且可以提出一个解决方案。这只是对记录的简短解释。

<TextBlock Text="{t:Translate 'import files', {Binding FileCount}}"/>

这需要一个继承自MarkupExtension的类TranslateExtension,其构造函数接受两个参数,一个String和一个Binding。将两个值存储在实例中。类的ProvideValue方法然后使用它获得的绑定,向它添加一个自定义转换器实例,并从binding.ProvideValue返回结果,它是一个BindingExpression实例IIRC。

public class TranslateExtension : MarkupExtension
{
    public TranslateExtension(string key, Binding countBinding)
    {
        // Save arguments to properties
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        countBinding.Converter = new TranslateConverter(key);
        return countBinding.ProvideValue(serviceProvider);
    }
}

转换器,比如TranslateConverter类,有一个接受一个参数的构造函数,一个String。这是我上面的TranslateExtension的关键参数。它会记得以后。

每当Count值发生变化(通过绑定)时,WPF将重新请求其值。它似乎从绑定源通过转换器走到显示它的表面。通过使用转换器,我们根本不必担心绑定,因为转换器将绑定的当前值作为方法参数获取,并且预计会返回其他内容。计算值(int)in,翻译文本(string)out。这是我的代码。

因此转换器的任务是将数字调整为配方文本。它使用存储的文本键。所以发生的事情基本上是一种有向后的数据流。我们需要将计数值作为主要信息处理,而不是将文本键作为主要信息和计数值添加到主要信息中,而只需使用文本键作为辅助参数来使其成为整体。这并不简单,但绑定需要成为主要触发器。由于密钥不会改变,因此可以在转换器的实例中存储。翻译文本的每个出现都有自己的转换器副本,每个副本都有一个编程的单独密钥。

这就是转换器的样子:

class TranslateConverter : IValueConverter
{
    private string key;
    public TranslateConverter(string key)
    {
        this.key = key;
    }
    public object Convert(object value, ...)
    {
        return Translator.Translate(key, (int) value);
    }
}

这就是魔术。添加错误处理和更多功能以获得解决方案。