2009-06-12 3 views
5

키를 기반으로 문자열을 번역 할 때 마크 업 확장을 만들었습니다. 예MarkupExtension 내부의 데이터 바인딩 값을 어떻게 해결합니까?

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

이제 내 키를 제공하기 위해 중첩 된 바인딩을 사용할 수 있기를 원합니다. 예 : 나는이 작업을 수행 할 때

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

은 내가 System.Windows.Data.Binding 객체를 얻는다. ServiceProvider을 ProvideValue를 호출하고 아래로 통과함으로써 나는 BindingExpression 얻을 수 있습니다 :

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; 

나는이 bindingExpression을 얻을 수 있지만,있는 DataItem 속성은 null입니다. 나는 이와 같은 제 바인딩을 테스트했습니다.

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

그리고 제대로 작동합니다.

아이디어가 있으십니까?

답변

0

toxvaerd's answer은 보편적이지 않습니다. 원래 바인딩에 이미 변환기가있는 경우 중단됩니다. 또는 변환기를 쓸 수 없습니다.

더 나은 해결책이 있습니다. 두 개의 생성자를 선언 할 수 있습니다. 두 번째 것은 BindingBase을 수락하며 바인딩이 사용될 때 XAML에 의해 호출됩니다. 바인딩 값을 해결하기 위해 우리는 개인 접속 속성을 선언 할 수 있습니다. 이를 위해 마크 업 확장의 대상 요소를 알아야합니다.

catch가 있습니다. 템플릿 내에서 마크 업 확장 프로그램을 사용할 때 대상 요소가 없습니다 (분명히). 이 경우 supposedProvideValue()return this을 사용합니다. 이렇게하면 템플릿을 적용 할 때 확장명이 다시 호출됩니다.

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

바인딩 값이 변경되면 ProvideValue가 다시 호출되지 않습니다. 이것에 대한 해결책이 있습니까? – Haytam

+0

@Haitam 질문은 바인딩의 가치를 해결하는 것이 었습니다. 변경 될 수 있다고 생각되면 대신 'Value'에 바인드하고 변환기를 사용하는 다른 바인딩을 반환 할 수 있습니다. – torvin

+0

첨부 된 건물의 작동 방식을 설명해 주시겠습니까? 나는 항상'target.GetValue()'에서'null '을 얻고있다. ... – spacer

2

바인딩의 가치를 얻으려면이 아닌 이되어야합니다. 너는 이것을하려고 시도조차하지 말아야한다. WPF는 멋진 리플렉션을 사용하여 바인딩을 해결하고 나를 신뢰합니다. 직접 시도하지 않아도됩니다.

내가 번역을 처리 걸린 TranslateConverter했다 : 염두에와 어쨌든

, 이것은 내가 실제로 좋은 해결책이다,하고 결국 무엇에 그런

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; 
} 

내 ,

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); 

바인딩은 WPF에 의해 해결되고 값으로 변환에 전달되는이 방법을 간단한 잠시 : TranslateExtension 단순히 이렇게 텍스트 키는 매개 변수로 변환기에 전달됩니다.

_targetObject_targetProperty은 ServiceProvider에서 가져옵니다.

+4

그 의미는 무엇입니까? 데이터 바인딩은 데이터 바인딩을 사용하여 값을 전송하고 최신 상태로 유지합니다. 그렇다면 바인딩에는 어떤 가치가 없습니까? 나는 똑같은 해결책을 찾고 있는데 질문에 대답하지 않았 으면 다른 대답을했다. A 변환기는 나를위한 옵션이 아닙니다. – ygoe

+0

@ygoe 내 [answer] (https : // stackoverflow.com/a/48090008/332528) – torvin

관련 문제