【问题标题】:MarkupExtension that uses a DataBinding value使用 DataBinding 值的 MarkupExtension
【发布时间】:2013-01-22 03:02:30
【问题描述】:

我正在尝试创建一个 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 分钟,那么它与只需要 1 分钟的情况不同。如果文本键“分钟”被定义为任何数字的“分钟”和计数为 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 内部,提供的代码仅将其推向正确的方向,但尚不清楚如何。我无法适应它来做任何有用的事情。

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

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

【问题讨论】:

  • 我认为在这种情况下,IValueConverterMarkupExtension 效果更好
  • 那会是什么样子? &lt;TextBlock Text="{Binding FileCount, Converter=???}"/&gt;?打字有点倒退。如果我想让语言字典在运行时可更改,那么这也需要绑定怎么办?

标签: wpf data-binding markup-extensions


【解决方案1】:

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

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

这需要一个类 TranslateExtension,继承自 MarkupExtension,构造函数接受两个参数,一个 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 类,有一个构造函数,它接受一个参数,一个字符串。这是我在上面的 TranslateExtension 中的关键论点。它会记住它以备后用。

只要 Count 值发生变化(它通过绑定),WPF 就会重新请求它的值。它似乎从绑定的源头,通过转换器,到达显示它的表面。通过使用转换器,我们根本不必担心绑定,因为转换器将绑定的当前值作为方法参数获取,并期望返回其他内容。计数值(int)输入,翻译文本(字符串)输出。这是我的代码。

因此,转换器的任务是使数字适应公式化的文本。它为此使用存储的文本密钥。所以发生的事情基本上是一种向后的数据流。与其将文本键作为主要信息并将计数值添加到其中,我们需要将计数值视为主要信息,并将文本键用作辅助参数以使其完整。这并不完全简单,但绑定需要成为主要触发器。由于密钥不会更改,因此可以将其永久存储在转换器的实例中。每次出现的翻译文本都会获得它自己的转换器副本,每个都有一个单独的键。

这是转换器的样子:

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

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

【讨论】:

  • 如果原始绑定已经有转换器,则此中断。有更好的solution
猜你喜欢
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
  • 2017-06-18
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多