使用 DataBinding 值的 MarkupExtension [英] MarkupExtension that uses a DataBinding value

查看:15
本文介绍了使用 DataBinding 值的 MarkupExtension的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个 WPF MarkupExtension 类,该类提供来自我的文本翻译类的翻译文本.翻译的东西很好用,但需要一个带有文本键的静态方法调用来返回翻译的文本.像这样:

I'm trying to create a WPF MarkupExtension class that provides translated text from my text translation class. The translation stuff works great, but requires a static method call with a text key to return the translated text. Like this:

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

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

Its speciality is that it accepts a counting value to provide better wordings.

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

另一个例子:如果某件事还需要 4 分钟,那么它与只需要一分钟是不同的词.如果将文本键分钟"定义为任何数字的分钟"和计数为 1 的分钟",则以下方法调用将返回要使用的正确单词:

Another example: If something takes yet 4 minutes, it's a different word than if it only takes one minute. If a text key "minutes" is defined as "Minuten" for any number and as "Minute" for a count of 1, the following method call will return the right word to use:

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

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

Now in a WPF application, there's a lot of XAML code and that contains lots of literal texts. To be able to translate them without getting nuts, I need a markup extension which I can pass my text key and that will return the translated text at runtime. This part is fairly easy. Create a class inheriting from MarkupExtension, add a constructor that accepts the text key as argument, store it in a private field, and let its ProvideValue method return a translation text for the stored key.

我真正的问题是:如何让我的标记扩展接受计数值,使其受数据约束,并且当计数值更改时翻译文本会相应更新?

My real problem is this: How can I make my markup extension accept a counting value in such a way that it's data-bound and the translation text will update accordingly when the count value changes?

应该这样使用:

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

每当 FileCount 的绑定值发生变化时,TextBlock 都必须接收一个新的文本值以反映该变化并仍然提供良好的措辞.

Whenever the binding value of FileCount changes, the TextBlock must receive a new text value to reflect the change and still provide a good wording.

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

I've found a similar-looking solution over there: http://blogs.microsoft.co.il/blogs/tomershamam/archive/2007/10/30/wpf-localization-on-the-fly-language-selection.aspx But as hard as I try to follow it, I can't understand what it does or why it even works. Everything seems to happen inside of WPF, the provided code only pushes it in the right direction but it's unclear how. I can't get my adaption of it to do anything useful.

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

I'm not sure whether it could be useful to let the translation language change at runtime. I think I'd need another level of bindings for that. To keep complexity low, I would not seek to do that until the basic version works.

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

At the moment there's no code I could show you. It's simply in a terrible state and the only thing it does is throwing exceptions, or not translating anything. Any simple examples are very welcome (if such thing exists in this case).

推荐答案

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

Nevermind, I finally found out how the referenced code works and could come up with a solution. Here's just a short explanation for the record.

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

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

This requires a class TranslateExtension, inherited from MarkupExtension, with a constructor accepting two parameters, one String and one Binding. Store both values in the instance. The classes' ProvideValue method then uses the binding it gets, adds a custom converter instance to it and returns the result from binding.ProvideValue, which is a BindingExpression instance 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 中的主要论点.它会记住它以备后用.

The converter, say of class TranslateConverter, has a constructor that accepts one parameter, a String. This is my key argument from the TranslateExtension above. It remembers it for later.

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

Whenever the Count value changes (it comes through the binding), WPF will request its value anew. It seems to walk from the source of the binding, through the converter, to the surface where it's displayed. By using a converter, we don't have to worry about the binding at all, because the converter gets the binding's current value as a method argument and is expected to return something else. Counting value (int) in, translated text (string) out. This is my code.

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

So it's the converter's task to adapt the number to a formulated text. It uses the stored text key for that. So what happens is basically a kinda backwards data flow. Instead of the text key being the main information and the count value being added to it, we need to treat the count value as the primary information and just use the text key as a side parameter to make it whole. This isn't exactly straightforward, but the binding needs to be the primary trigger. Since the key won't change, it can be stored for good in the instance of the converter. And every occurence of a translated text gets its own copy of the converter, each with an individual key programmed in.

这就是转换器的样子:

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

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

That's the magic. Add the error handling and more features to get the solution.

这篇关于使用 DataBinding 值的 MarkupExtension的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆