2009-06-12 20 views
5

Anahtarlara göre dizeleri çevirmek için işaretleme uzantısı yaptım. ÖrnekVeritabanının değerini bir MarkupExtension içinde nasıl çözebilirim?

<TextBlock Text="{Translate myKey}" /> 

Şimdi anahtarlarımı sağlamak için iç içe geçmiş bağlamaları kullanabilmek istiyorum. Örnek: Bir System.Windows.Data.Binding nesnesi aldığımda,

<TextBlock Text="{Translate {Binding KeyFromDataContext}}" /> 

ServiceProvider ProvideValue arama ve aşağı geçerek bir BindingExpression alabilirsiniz:

var binding = Key as Binding; 
if (binding == null) { 
    return null; 
} 
var bindingExpression = binding.ProvideValue(_serviceProvider) as BindingExpression; 
if (bindingExpression == null) { 
    return null; 
} 
var bindingKey = bindingExpression.DataItem; 

Bu bindingExpression alabilirsiniz, ama Dataıtem özelliği null olur. Bağlantımı bu

gibi test ettim ve iyi çalışıyor.

Herhangi bir fikrin var mı?

cevap

0

toxvaerd's answer evrensel değildir. Orijinal ciltleme zaten bir dönüştürücüye sahipse kırılır. Veya dönüştürücü yazarken mümkün değildir.

Daha iyi bir çözüm var. İki kurucu ilan edebiliriz. Bir bağlayıcı kullanıldığında, BindingBase kabul eden ikinci XAML tarafından çağrılacaktır. Bağlantının değerini çözmek için özel ekli bir mülk bildirebiliriz. Bunun çalışması için işaretleme uzantısının hedef elemanını bilmemiz gerekiyor.

Yakalama var: işaretleme uzantısı bir şablon içinde kullanıldığında, hiçbir hedef öğe (açıkça) yoktur. Bu durumda, ProvideValue() numaralı telefondan return this'u kullanmak için supposed'sunuz - bu şekilde şablon uygulandığında uzantı tekrar çağrılacaktır.

public class TranslateExtension : MarkupExtension 
{ 
    private readonly BindingBase _binding; 

    public TranslateExtension(BindingBase binding) 
    { 
     _binding = binding; 
    } 

    public TranslateExtension(string key) 
    { 
     Key = key; 
    } 

    [ConstructorArgument("key")] 
    public string Key { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (_binding != null) 
     { 
      var pvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); 
      var target = pvt.TargetObject as DependencyObject; 

      // if we are inside a template, WPF will call us again when it is applied 
      if (target == null) 
       return this; 

      BindingOperations.SetBinding(target, ValueProperty, _binding); 
      Key = (string)target.GetValue(ValueProperty); 
      BindingOperations.ClearBinding(target, ValueProperty); 
     } 

     // now do the translation using Key 
     return ...; 
    } 

    private static readonly DependencyProperty ValueProperty = 
     DependencyProperty.RegisterAttached("Value", typeof(string), typeof(TranslateExtension)); 
} 
+0

Bağlantı değeri değiştiğinde, ProvideValue yeniden çağrılmıyor mu? Bunun için herhangi bir çözüm var mı? – Haytam

+0

@Haitam, sorunun bağlayıcının değerini çözmekti. Değişebileceğinden şüpheleniyorsanız - bunun yerine "Değer" e bağlanan ve dönüştürücü kullanan başka bir bağ getirebilirsiniz. – torvin

+0

Ekli mülkün burada nasıl çalıştığını açıklayabilir misiniz? Hedef.GetValue() 'dan 'null' ı her zaman alıyorum ... – spacer

2

Bir bağlamanın değerini almak içindeğil mümkündür. Bunu yapmaya bile çalışmamalısın. WPF, bağları çözmek ve bana güvenmek için bazı süslü yansıma kullanır - kendiniz denemeye başlamıyorsunuz.

Ben çeviri hallettim bir TranslateConverter yapılan: düşünülerek Neyse

, bu aslında güzel bir çözüm olan yapıyor sona budur içinde Sonra

public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
{ 
    var key = value as string ?? parameter as string; 

    if (key != null) 
    { 
    // Do translation based on the key 

    } 
    return null; 
} 

benim ,

var binding = Key as Binding ?? new Binding{Mode = BindingMode.OneWay}; 
binding.Converter = new TranslateConverter(_targetObject, _targetProperty, Dictionary, Converter); 
binding.ConverterParameter = Key is Binding ? null : Key as string; 

return binding.ProvideValue(serviceProvider); 

bağlayıcı bir WPF tarafından çözümlenir ve değer olarak dönüştürücü geçirilir Bu şekilde basit iken: TranslateExtension Ben sadece bunu metin tuşu dönüştürücüye bir parametre olarak aktarılır.

_targetObject ve _targetProperty ServiceProvider'dan edinilebilir.

+4

Bu ne anlama geliyor? Bir veri bağlamasının bir değeri vardır ve sadece bir değeri taşımak ve güncel tutmak için kullanır. Bir bağın nasıl bir değeri olmaz? Aynı çözümü arıyorum ama sorunuza cevap vermediniz, başka bir şey cevapladınız. Bir çevirici benim için bir seçenek değil. – ygoe

+0

@ygoe [yanıtı] kontrol et (https: // stackoverflow.com/a/48090008/332528) – torvin

İlgili konular