2011-09-16 24 views
11

Tôi thấy trực tuyến 2 cách tiếp cận khác nhau để tăng cường một IValueConverter. Một trong số họ đã mở rộng một ValueConverter từ MarkupExtension, một cái khác từ DependencyObject. Tôi không thể mở rộng từ cả hai, vì vậy tôi tự hỏi nếu có ai tốt hơn khác?Cải tiến IValueConverter - MarkupExtension hoặc DependencyObject?

+0

Tôi đoán nó phụ thuộc vào những gì bạn đang cố gắng đạt được. Bạn có thể thêm một số chi tiết nữa không? –

Trả lời

33

Xuất phát từ mỗi cung cấp cho bạn loại khác nhau của sức mạnh và tính linh hoạt:

  • Xuất phát từ MarkupExtension phép bạn sử dụng bộ chuyển đổi giá trị mà không làm cho nó một nguồn tài nguyên tĩnh, như mô tả dưới đây:

    public class DoubleMe : MarkupExtension, IValueConverter 
    { 
        public override object ProvideValue(IServiceProvider serviceProvider) 
        { 
         return this; 
        } 
        public object Convert(object value, /*rest of parameters*/) 
        { 
         if (value is int) 
         return (int)(value) * 2; //double it 
         else 
         return value.ToString() + value.ToString(); 
        } 
        //... 
    } 
    

    Trong XAML, bạn có thể trực tiếp sử dụng nó mà không cần tạo một StaticResource:

    <TextBlock Text="{Binding Name, Converter={local:DoubleMe}}"/> 
    <TextBlock Text="{Binding Age, Converter={local:DoubleMe}}"/> 
    

    Mã như vậy rất tiện dụng khi gỡ lỗi, vì bạn chỉ có thể viết local:DebugMe và sau đó có thể gỡ lỗi DataContext của điều khiển mà bạn sử dụng nó.

  • Xuất phát từ DependencyObject cho phép bạn configure bộ chuyển đổi giá trị với một số ưu đãi về một cách biểu cảm hơn, như mô tả dưới đây:

    public class TruncateMe : DependencyObject, IValueConverter 
    { 
        public static readonly DependencyProperty MaxLengthProperty = 
         DependencyProperty.Register("MaxLength", 
                 typeof(int), 
                 typeof(TruncateMe), 
                 new PropertyMetadata(100)); 
        public int MaxLength 
        { 
         get { return (int) this.GetValue(MaxLengthProperty); } 
         set { this.SetValue(MaxLengthProperty, value); } 
        } 
    
        public object Convert(object value, /*rest of parameters*/) 
        { 
         string s = value.ToString(); 
         if (s.Length > MaxLength) 
          return s.Substring(0, MaxLength) + "..."; 
         else 
          return s; 
        } 
        //... 
    } 
    

    Trong XAML, bạn có thể trực tiếp sử dụng nó như:

    <TextBlock> 
        <TextBlock.Text> 
         <Binding Path="FullDescription"> 
          <Binding.Converter> 
          <local:TruncateMe MaxLength="50"/> 
          </Binding.Converter> 
         </Binding> 
        </TextBlock.Text> 
    

    Nó làm gì? Nó cắt ngắn chuỗi FullDescription nếu nó có nhiều hơn 50 ký tự!

@crazyarabian nhận xét rằng:

tuyên bố của bạn "Xuất phát từ DependencyObject cho phép bạn cấu hình bộ chuyển đổi giá trị với một số ưu đãi về cách biểu cảm hơn" không phải là độc quyền cho DependencyObject như bạn có thể tạo cùng một thuộc tính MaxLength trên một MarkupExtension dẫn đến <TextBlock Text="Binding Age, Converter={local:DoubleMe, MaxLength=50}}"/>. Tôi cho rằng một MarkupExtension là biểu cảm hơn và ít chi tiết hơn.

Điều đó đúng. Nhưng thế thì điều đó không bị ràng buộc; có nghĩa là, khi bạn xuất phát từ MarkupExtension, thì bạn không thể làm:

MaxLength="{Binding TextLength}" 

Nhưng nếu bạn lấy được chuyển đổi của bạn từ DependencyObject, sau đó bạn có thể làm các việc trên. Theo nghĩa đó, nó là biểu cảm hơn so với MarkupExtension.

Lưu ý rằng thuộc tính mục tiêu phải là DependencyProperty cho Binding để hoạt động.MSDN says,

  • Mỗi ràng buộc thường có bốn thành phần: một ràng buộc mục tiêu đối tượng, thuộc tính mục tiêu, một nguồn ràng buộc, và một con đường với giá trị trong nguồn ràng buộc để sử dụng. Ví dụ, nếu bạn muốn để ràng buộc các nội dung của một TextBox đến thuộc tính Name của một đối tượng nhân viên, đối tượng mục tiêu của bạn là TextBox, tài sản mục tiêu là các Văn bản tài sản, giá trị sử dụng là Tên và đối tượng nguồn là đối tượng nhân viên .

  • Thuộc tính đích phải là thuộc tính phụ thuộc.

+0

Tôi thấy dự án Chuyển đổi của Kent Boogaart trên Codeplex mở rộng tất cả các IValueConverter của ông đã viết từ DependencyObject. http://wpfconverters.codeplex.com/SourceControl/changeset/view/61942# – michael

+0

@Nawaz Phát biểu của bạn "Bắt nguồn từ" DependencyObject' cho phép bạn định cấu hình trình chuyển đổi giá trị với một số tùy chọn theo cách biểu cảm hơn "không độc quyền đối với 'DependencyObject' vì bạn có thể tạo cùng một thuộc tính' MaxLength' trên 'MarkupExtension', kết quả là' '. Tôi sẽ lập luận rằng một 'MarkupExtension' là biểu cảm hơn và ít chi tiết hơn. – sellmeadog

+0

@crazyarabian: Có. Bạn có thể làm điều đó, Nhưng thế thì điều đó không bị ràng buộc. Bạn không thể làm 'MaxLength =" {Binding TextLength} "'. – Nawaz

3

Vì nó my library bạn đang trích dẫn như một ví dụ về chuyển đổi mà mở rộng DependencyObject, tôi nghĩ rằng nó phù hợp để giải thích bản thân mình.

Tôi thực sự bắt đầu bằng cách đơn giản triển khai IValueConverter với Object làm lớp cơ sở của tôi. Lý do duy nhất tôi chuyển sang mở rộng DependencyObject là cho phép một kỹ thuật - được tiên phong bởi Josh Smith - được gọi là phân nhánh ảo. Bạn có thể đọc về kỹ thuật đó here.

Giả sử bạn muốn làm một cái gì đó như thế này:

<UserControl.Resources> 
    <con:CaseConverter Casing="{Binding SomeProperty}"/> 
</UserControl.Resources> 

này sẽ không làm việc vì các nguồn lực không nằm trong cây thị giác, và do đó các ràng buộc sẽ thất bại. Ảo phân nhánh hacks xung quanh tình trạng khó xử này ít, cho phép bạn thực hiện như một ràng buộc. Tuy nhiên, nó vẫn dựa - giống như bất kỳ ràng buộc WPF nào khác - trên mục tiêu là DependencyObject. Do đó, nếu tôi chỉ cần triển khai IValueConverter mà không cần mở rộng DependencyObject, bạn sẽ bị loại trừ khỏi việc sử dụng các nhánh ảo.

Bây giờ, nếu tôi hoàn toàn trung thực, tôi không chắc chắn tôi vẫn sẽ làm điều này nếu tôi có thời gian của tôi một lần nữa. Tôi chưa bao giờ thực sự để tự mình sử dụng chi nhánh ảo - tôi chỉ muốn bật kịch bản. Tôi thậm chí có thể thay đổi điều này trong một phiên bản tương lai của thư viện của tôi. Vì vậy, lời khuyên của tôi sẽ được gắn vào một lớp cơ sở của Object (hoặc một dẫn xuất đơn giản của chúng) trừ khi bạn thực sự nghĩ rằng bạn sẽ cần phân nhánh ảo.

+0

Điều này có hoạt động trong Silverlight không? – Shimmy

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