我正在嘗試為 WPF 創建一個 MarkupExtension 以用于翻譯。我在這里發現了一些類似的問題,包括
使用 DataBinding 值的 MarkupExtension
如何決議 MarkupExtension 中資料系結的值?
最終,這導致Torvin的回應看起來非常有希望。但是,就像評論中的一個人一樣,我有一個問題,即 獲得的值target.GetValue()總是回傳空值。
這是一些代碼。
最終我有一組靜態類,其中包含一個靜態 KeyDefinition 物件,如下所示
Public class KeyDefinition
{
Public string Key {get; set;}
Public string DefaultValue {get; set;}
}
鍵與 JSON 資源相關聯,而 DefaultValue 是英文翻譯,我們可以將其用于 xaml 的設計時顯示。
本地化通過像這樣的靜態類發生 Localize.GetResource(key)
我的目標是像這樣撰寫 XAML
<TextBlock Text="{Localize {Binding KeyDefinitionFromDataContext}}">
其中KeyDefinitionFromDataContext是視圖模型中的一個屬性,它回傳對KeyDefinition物件的參考。
根據 Torvin 的回應,我像這樣創建了一個 MarkupExtension
public class LocalizeExtension : MarkupExtension
{
private readonly BindingBase _binding;
private static readonly DependencyProperty _valueProperty = DependencyProperty.RegisterAttached("Value", typeof(KeyDefinition), typeof(LocalizeExtension));
[ConstructorArgument("keyDefinition")
public KeyDefinition KeyDefinition {get; set;}
public LocalizeExtension(Binding binding)
{
_binding = binding;
}
public LocalizeExtension(KeyDefinition keyDefinition)
{
KeyDefinition = keyDefinition;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var pvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
var target = pvt.TargetObject as DependencyObject;
var property = pvt.TargetProperty as DependencyProperty;
//If inside a template, WPF will call again when its applied
if (target == null)
return this;
BindingOperations.SetBinding(target, property, _binding);
KeyDefinition = (KeyDefinition)target.GetValue(_valueProperty);
BindingOperations.ClearBinding(target, property);
return Localize.GetResource(KeyDefinition.Key);
}
}
現在請原諒我,因為我通常不做WPF作業,但這個任務落到了我的身上。每當我運行此代碼時,回傳的值總是Null. 我試過直接使用字串而不是“KeyDefinition”物件,但遇到了同樣的問題。
我認為這里讓我感到困惑的是目標上的 DependencyProperty 是如何設定的,因為它是私有的。
任何幫助表示贊賞。謝謝!
uj5u.com熱心網友回復:
這不是它的作業原理。的結果MarkupExtension總是null,因為那是你回傳的。您必須知道Binding(the BindingExpression) 在呼叫擴展時未決議。XAML 引擎呼叫擴展并在Binding. 通常,MarkupExtension將回傳 的結果Binding.ProvideValue(serviceProvider),即 a BindingExpressionBase。XAML 引擎稍后將使用此運算式通過實際附加系結來生成資料。
換句話說,您過早地回傳結果。
除此之外,您還必須知道MarkupExtension.ProvideValue只被呼叫一次。這意味著您的擴展不處理屬性更改(以防系結源更改)并且清除系結不是系結的所需處理。它實際上甚至無法處理OneTime系結模式。
在本地化的背景關系中,期望源屬性發生變化是非常有意義的,至少在用戶更改本地化時是這樣。
您的代碼中有更多錯誤,例如未設定的_valueProperty欄位。DependencyProperty在不擴展的型別上定義 a 的目的是什么DependencyObject?它甚至是私人的!您還應該避免混合屬性和欄位。更好地定義(只讀)屬性而不是欄位。從您的擴展回傳this( type 的實體MarkupExtension)在預期型別不是object例如 a string- return的情況下不起作用null。
你想要的很容易實作。
首先,您必須將 附加Binding到代理物件以允許系結引擎激活BindingExpression(在示例中這是BindingResolver類)。
其次,您必須配置傳入系結以在目標更新時發出通知。然后監聽Binding.TargetUpdated事件實作OneWay系結。要實作TwoWay和OneWayToSource系結模式,還必須啟用和觀察Binding.SourceUpdated事件。
最后,從源/系結代理檢索更改的值以將其設定為MarkupExtension.
由于資料系結通常涉及DataContext作為源,即需要可視化樹才能決議,因此系結代理是一個簡單的附加屬性。這樣做的好處是我們可以使用DataContext目標元素的原始元素,而不必擔心如何將我們的代理注入到可視化樹中。
本地化擴展程式
public class LocalizeExtension : MarkupExtension
{
private Binding Binding { get; };
private DependencyObject LocalizationTarget { get; set; }
private DependencyProperty LocalizationTargetProperty { get; set; }
private object LocalizationSource { get; set; }
private string LocalizationPropertyName { get; set; }
private bool IsInitialized { get; set; }
public LocalizeExtension(Binding binding)
{
this.Binding = binding;
this.Binding.NotifyOnTargetUpdated = true;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var serviceProvider = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
this.LocalizationTarget = serviceProvider.TargetObject as DependencyObject;
// If inside a template, WPF will call again when its applied
if (this.LocalizationTarget == null)
{
return null;
}
this.LocalizationTargetProperty = serviceProvider.TargetProperty as DependencyProperty;
BindingOperations.SetBinding(this.LocalizationTarget, BindingResolver.ResolvedBindingValueProperty, this.Binding);
Binding.AddTargetUpdatedHandler(this.LocalizationTarget, OnBindingSourceUpdated);
return null;
}
private void OnBindingSourceUpdated(object sender, EventArgs e)
{
if (!this.IsInitialized)
{
InitializeLocalizationSourceInfo();
}
LocalizeBindingSource();
}
private void InitializeLocalizationSourceInfo()
{
BindingExpression bindingExpression = BindingOperations.GetBindingExpression(this.LocalizationTarget, BindingResolver.ResolvedBindingValueProperty);
this.LocalizationSource = bindingExpression.ResolvedSource;
this.LocalizationPropertyName = bindingExpression.ResolvedSourcePropertyName;
this.IsInitialized = true;
}
private void LocalizeBindingSource()
{
object unlocalizedValue = BindingResolver.GetResolvedBindingValue(this.LocalizationTarget);
object localizedValue = LocalizeValue(unlocalizedValue);
this.LocalizationTarget.SetValue(this.LocalizationTargetProperty, localizedValue);
}
private object LocalizeValue(object value)
{
return value is KeyDefinition keyDefinition
? Localize.GetResource(keyDefinition.Key)
: string.Empty;
}
}
BindingResolver.cs
class BindingResolver : DependencyObject
{
public static object GetResolvedBindingValue(DependencyObject obj) => (object)obj.GetValue(ResolvedBindingValueProperty);
public static void SetResolvedBindingValue(DependencyObject obj, object value) => obj.SetValue(ResolvedBindingValueProperty, value);
public static readonly DependencyProperty ResolvedBindingValueProperty =
DependencyProperty.RegisterAttached(
"ResolvedBindingValue",
typeof(object),
typeof(BindingResolver),
new PropertyMetadata(default));
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/334473.html
