2009-06-12 22 views
5

Tôi đã tạo phần mở rộng đánh dấu để dịch chuỗi dựa trên khóa. Ví dụLàm cách nào để giải quyết giá trị của một dữ liệu trong một MarkupExtension?

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

Bây giờ tôi muốn có thể sử dụng các kết buộc lồng nhau để cung cấp khóa của mình. Ví dụ:

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

Khi tôi làm điều này, tôi nhận được đối tượng System.Windows.Data.Binding. Bằng cách gọi cho OfferValue và chuyển xuống ServiceProvider tôi có thể nhận được một 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; 

Tôi có thể nhận được liên kết nàyExpression, nhưng thuộc tính DataItem là rỗng. Tôi đã thử nghiệm sự ràng buộc của mình như thế này

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

và nó hoạt động tốt.

Bất kỳ ý tưởng nào?

Trả lời

0

toxvaerd's answer không phổ biến. Nó phá vỡ nếu ràng buộc ban đầu đã có một công cụ chuyển đổi. Hoặc khi viết một trình biến đổi là không thể.

Có giải pháp tốt hơn. Chúng ta có thể khai báo hai hàm tạo. Cái thứ hai chấp nhận BindingBase sẽ được gọi bởi XAML khi một ràng buộc được sử dụng. Để giải quyết giá trị của ràng buộc, chúng ta có thể khai báo một thuộc tính đính kèm riêng. Để làm việc này, chúng ta cần biết phần tử đích của phần mở rộng đánh dấu.

Có một điểm bắt buộc: khi tiện ích mở rộng đánh dấu được sử dụng bên trong mẫu, không có phần tử đích (rõ ràng). Trong trường hợp này, bạn là supposed để sử dụng return this trong ProvideValue() - theo cách này, tiện ích sẽ được gọi lại khi mẫu được áp dụng.

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

Điều gì xảy ra nếu giá trị ràng buộc thay đổi, GiveValue không được gọi lại ngay? Có giải pháp nào cho điều này? – Haytam

+0

@Haitam câu hỏi là về giải quyết giá trị của ràng buộc. Nếu bạn nghi ngờ nó có thể thay đổi - thay vào đó bạn có thể trả về một ràng buộc khác liên kết với 'Giá trị' và sử dụng trình chuyển đổi. – torvin

+0

Bạn có thể giải thích cách thức tài sản đính kèm tại đây hoạt động không? Tôi luôn luôn nhận được 'null' từ' target.GetValue() '... – spacer

2

Đó là không phải có thể nhận giá trị của ràng buộc. Bạn không phải là cố gắng để làm điều này. WPF sử dụng một số phản ánh lạ mắt để giải quyết các ràng buộc và tin tưởng tôi - bạn không wan't để bắt đầu cố gắng mà mình.

Dù sao với ý nghĩ đó, đây là những gì tôi đã kết thúc làm, mà thực sự là một giải pháp tốt đẹp:

tôi đã thực hiện một TranslateConverter rằng đã chăm sóc của bản dịch:

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

Sau đó, trong tôi TranslateExtension tôi chỉ đơn giản làm điều này:

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

bằng cách này một ràng buộc đã được giải quyết bởi WPF và được truyền cho bộ chuyển đổi như giá trị, trong khi một đơn giản text-key được truyền tới bộ chuyển đổi như một tham số.

_targetObject_targetProperty được lấy từ ServiceProvider.

+4

Điều đó có nghĩa là gì? Một ràng buộc dữ liệu của một và chỉ sử dụng nó để vận chuyển một giá trị và giữ cho nó up-to-date. Làm thế nào có thể một ràng buộc không có một giá trị sau đó? Tôi đang tìm giải pháp tương tự nhưng bạn không trả lời câu hỏi của mình, bạn đã trả lời một câu hỏi khác. Một công cụ chuyển đổi không phải là một lựa chọn cho tôi. – ygoe

+0

@ygoe kiểm tra [answer] của tôi (https: // stackoverflow.com/a/48090008/332528) – torvin

Các vấn đề liên quan