2013-02-06 11 views
9

Ich versuche, eine WPF-MarkupExtension-Klasse zu erstellen, die übersetzten Text aus meiner Textübersetzungsklasse bereitstellt. Die Übersetzungsfunktion funktioniert gut, erfordert jedoch einen statischen Methodenaufruf mit einem Textschlüssel, um den übersetzten Text zurückzugeben. Wie folgt:MarkupExtension, das einen DataBinding-Wert verwendet

Seine Spezialität ist, dass es einen Zählwert akzeptiert, um bessere Formulierungen zu bieten.

Ein anderes Beispiel: Wenn etwas noch 4 Minuten dauert, ist es ein anderes Wort als wenn es nur eine Minute dauert. Wenn ein Textschlüssel „Minuten“ sind definiert als „Minuten“ für eine beliebige Anzahl und als „Minute“ für eine Anzahl von 1, kehrt der folgende Methodenaufruf, das richtige Wort zu verwenden:

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

Jetzt in einem WPF Anwendung gibt es viel XAML-Code und das enthält viele literale Texte. Um sie übersetzen zu können, ohne verrückt zu werden, brauche ich eine Markup-Erweiterung, die ich meinen Textschlüssel weitergeben kann und die den übersetzten Text zur Laufzeit zurückgibt. Dieser Teil ist ziemlich einfach. Erstellen Sie eine Klasse, die von MarkupExtension erbt, fügen Sie einen Konstruktor hinzu, der den Textschlüssel als Argument akzeptiert, speichern Sie ihn in einem privaten Feld, und lassen Sie die ProvideValue-Methode einen Übersetzungstext für den gespeicherten Schlüssel zurückgeben.

Mein wirkliches Problem ist dies: Wie kann ich meine Markup-Erweiterung akzeptieren einen Zählwert in einer Weise, dass es Daten gebunden ist und die Übersetzung Text wird entsprechend aktualisiert, wenn der Zählwert ändert?

Es sollte wie folgt verwendet werden:

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

Jedes Mal, wenn die Bindungswert von Filecount ändert, wird der Textblock einen neuen Textwert erhalten muss die Änderung widerzuspiegeln und noch eine gute Formulierung bereitzustellen.

Ich habe eine ähnlich aussehende Lösung dort gefunden: http://blogs.microsoft.co.il/blogs/tomershamam/archive/2007/10/30/wpf-localization-on-the-fly-language-selection.aspx Aber so hart wie ich versuche, es zu folgen, kann ich nicht verstehen, was es tut oder warum es sogar funktioniert. Alles scheint innerhalb von WPF zu passieren, der mitgelieferte Code bringt es nur in die richtige Richtung, aber es ist unklar, wie. Ich kann meine Anpassung nicht dazu bringen, etwas Nützliches zu tun.

Ich bin nicht sicher, ob es nützlich sein könnte, die Übersetzungssprache zur Laufzeit ändern zu lassen. Ich denke, ich würde dafür ein anderes Level an Bindungen brauchen. Um die Komplexität niedrig zu halten, würde ich das erst versuchen, wenn die Basisversion funktioniert.

Im Moment gibt es keinen Code, den ich Ihnen zeigen könnte. Es ist einfach in einem schrecklichen Zustand und das einzige, was es tut, ist Ausnahmen zu werfen oder nichts zu übersetzen. Alle einfachen Beispiele sind sehr willkommen (wenn so etwas in diesem Fall existiert).

+0

Ich denke ein 'IValueConverter' würde besser funktionieren als eine' MarkupExtension' für dieses Szenario –

+0

Wie würde das aussehen? ''? Ein bisschen zurück zum Tippen. Was, wenn ich das Sprachwörterbuch zur Laufzeit änderbar machen wollte, so dass auch eine Bindung nötig wäre? – ygoe

Antwort

15

Nevermind, habe ich endlich herausgefunden, wie der referenzierte Code funktioniert und könnte eine Lösung finden. Hier ist nur eine kurze Erklärung für die Aufzeichnung.

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

Dies erfordert eine Klasse TranslateExtension, von Markupextension geerbt, mit einem Konstruktor akzeptiert zwei Parameter, einen String und eine Bindung. Speichern Sie beide Werte in der Instanz. Die ProvideValue-Methode der Klassen verwendet dann die Bindung, die sie erhält, fügt eine benutzerdefinierte Konvertierungsinstanz hinzu und gibt das Ergebnis von binding.ProvideValue zurück, das eine BindingExpression-Instanz IIRC ist.

Der Konverter, sagen der Klasse TranslateConverter, hat einen Konstruktor, der einen Parameter akzeptiert, einen String. Dies ist mein Schlüsselargument aus der obigen TranslateExtension. Es erinnert sich daran für später.

Immer wenn der Count-Wert sich ändert (es kommt durch die Bindung), wird WPF seinen Wert erneut anfordern. Es scheint von der Quelle der Bindung durch den Konverter zu der Oberfläche zu laufen, auf der es angezeigt wird. Durch die Verwendung eines Konverters müssen wir uns nicht um die Bindung kümmern, da der Konverter den aktuellen Wert der Bindung als Methodenargument erhält und etwas anderes erwartet. Zählwert (int) in, übersetzter Text (string) out. Das ist mein Code.

Es ist also die Aufgabe des Konverters, die Zahl an einen formulierten Text anzupassen. Es verwendet den gespeicherten Textschlüssel dafür. Was passiert, ist im Grunde ein gewisser Rückwärtsdatenfluss. Anstatt dass der Textschlüssel die Hauptinformation ist und der Zählwert hinzugefügt wird, müssen wir den Zählwert als primäre Information behandeln und einfach den Textschlüssel als Seitenparameter verwenden, um ihn ganz zu machen. Dies ist nicht gerade einfach, aber die Bindung muss der primäre Auslöser sein. Da sich der Schlüssel nicht ändert, kann er in der Instanz des Konverters für immer gespeichert werden. Und jedes Auftreten eines übersetzten Text bekommt seine eigene Kopie des Wandlers, die jeweils mit einem individuellen Schlüssel programmiert in

Dies ist, was der Konverter aussehen könnte.

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

Das ist die Magie. Fügen Sie die Fehlerbehandlung und weitere Funktionen hinzu, um die Lösung zu erhalten.

+0

Dieser ** wird ** brechen, wenn die ursprüngliche Bindung bereits einen Konverter hatte. Es gibt eine bessere [Lösung] (https://stackoverflow.com/a/48090008/332528) – torvin

Verwandte Themen