2012-04-26 76 views
5

Tôi đang làm việc trên Custom MarkupExtension trong đó tôi cần một tham số không phải chuỗi từ XAML để xây dựng đối tượng mới. Có thể sử dụng một tham số không ràng buộc tham số trên một trường trong phạm vi datacontext không?MarkupExtension với các tham số ràng buộc

Nói cách khác, làm cách nào tôi có thể làm điều gì đó như thế này?

<ListBox ItemsSource="{Binding Source={local:MyMarkupExtension {x:Type Button},IncludeMethods={Binding Source=CustomerObject.IsProblematic}}}" /> 

nơi IncludeMethods=CustomerObject.IsProblematic cho tôi lỗi này: ràng buộc không thể được đặt trên các loại tài sản của 'TypeDescriptorExtension' 'IncludeMethods'. Chỉ có thể đặt 'Binding' trên DependencyProperty của DependencyObject.

Có ai có thể giúp tôi không?

nhờ

Trả lời

9

A 'ràng buộc' chỉ có thể được đặt trên một thuộc tính phụ thuộc của một DependencyObject - đó là sự thật. Vấn đề là lớp MarkupExtension không xuất phát từ DependencyObject, đó là lý do tại sao không thể đặt ràng buộc trên các thuộc tính của nó.

[EDIT]

Cách giải quyết là sử dụng ValueConverters. Cách giải quyết khác là thay đổi ngôn ngữ C# để cho phép đa thừa kế. Nhân tiện, trong Silverlight MarkupExtension triển khai giao diện IMarkupExtension, vì vậy tôi đã cố gắng triển khai nó trong tiện ích tùy chỉnh của mình và lấy nó từ DependecyObject, thêm DependencyProperty vào đó và đặt ràng buộc với nó. Nó không sụp đổ, nhưng ràng buộc thực sự được thiết lập sau khi ProvideValue() được gọi. Vì vậy, ngay cả trong Silverlight không có giải pháp (hoặc nó là khó khăn - xem liên kết được cung cấp trong Klaus78's answer). Trong WPF MarkupExtension không thực hiện bất kỳ giao diện nào, do đó bạn không thể liên kết với các thuộc tính của nó.

+0

ai cũng có thể gợi ý cho tôi một cách giải quyết? – user1351709

+0

xin vui lòng xem chỉnh sửa của tôi – EvAlex

+17

Thay đổi ngôn ngữ C# để cho phép đa thừa kế không chính xác những gì tôi sẽ gọi là "workaround";) –

0

Liên kết này là thông tin về

Custom Markup Extension with bindable properties

EDIT Có người làm cho tôi lưu ý rằng đây chỉ hoạt động cho Silverlight, bởi vì trong WPF MarkupExtension không thực hiện giao diện IMarkupExtension. (Cảm ơn bạn EvAlex)

+0

Nó chỉ hoạt động với Silverlight, vì trong WPF MarkupExtension không thực hiện giao diện IMarkupExtension – EvAlex

-1

Tôi đã tìm thấy giải pháp cho sự cố này.
Ý tưởng chính là xác định thuộc tính đính kèm cho mỗi tham số yêu cầu ràng buộc.

public class MarkupExtensionWithBindableParam : MarkupExtension 
{ 
    public BindingBase Param1 { get; set; } // its necessary to set parameter type as BindingBase to avoid exception that binding can't be used with non DependencyProperty 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; 
     DependencyObject targetObject; 
     DependencyProperty targetProperty; 

     if (target != null && target.TargetObject is DependencyObject && target.TargetProperty is DependencyProperty) 
     { 
      targetObject = (DependencyObject)target.TargetObject; 
      targetProperty = (DependencyProperty)target.TargetProperty; 
     } 
     else 
     { 
      return this; // magic 
     } 

     // Bind the Param1 to attached property Param1BindingSinkProperty 
     BindingOperations.SetBinding(targetObject, MarkupExtensionWithBindableParam.Param1BindingSinkProperty, Param1); 

     // Now you can use Param1 

     // Param1 direct access example: 
     object param1Value = targetObject.GetValue(Param1BindingSinkProperty); 

     // Param1 use in binding example: 
     var param1InnerBinding = new Binding() { Source = targetObject, Path = new PropertyPath("(0).SomeInnerProperty", Param1BindingSinkProperty) }); // binding to Param1.SomeInnerProperty 
     return param1InnerBinding.ProvideValue(serviceProvider); // return binding to Param1.SomeInnerProperty 
    } 

    private static DependencyProperty Param1BindingSinkProperty = DependencyProperty.RegisterAttached("Param1BindingSink", typeof(object)// set the desired type of Param1 for at least runtime type safety check 
         , typeof(MarkupExtensionWithBindableParam), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits)); 
} 

Cách sử dụng rất đơn giản:

<TextBlock Text={local:MarkupExtensionWithBindableParam Param1={Binding Path="SomePathToParam1"}}/> 
+0

Có một vấn đề với ví dụ * Usage *. Không đánh dấu phải được trong dấu ngoặc kép? – OmegaMan

+1

dường như không hoạt động; param1Value luôn là null – esskar

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