2009-04-22 39 views
6

Tôi đang cố gắng ràng buộc thuộc tính Văn bản của TextBlock theo một cách rất năng động. Tôi cần lấy Path từ một đối tượng bên dưới.Làm cách nào để liên kết thuộc tính Binding.Path với dữ liệu cơ bản?

Đây là DataTemplate:

<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Path=???} /> 
</DataTemplate> 

Đối tượng DummyClass có một tài sản có tên là "FieldValuePath" - con đường mà cần phải được đặt nơi ??? Là.

Ý tưởng đằng sau điều này là mẫu dữ liệu được cho là GUI để xem/chỉnh sửa bất kỳ thuộc tính nào của bất kỳ đối tượng nào. Vì vậy, nó là loại thích hợp hơn để có thể tuyên bố XAML mà sẽ ràng buộc một số điều khiển (textboxes, textblocks, datepickers, vv) cho một tài sản nhất định.

Có lẽ ai cũng có bất kỳ đề xuất nào về cách triển khai điều đó?

Trả lời

7

Nếu bạn tạo ràng buộc trong mã phía sau thì bạn có thể làm cho nó hoạt động. Ví dụ: mã đơn giản được tạo ràng buộc là:

Binding binding = new Binding("BindingPath"); 
binding.Mode = BindingMode.TwoWay; 
BindingOperations.SetBinding(textBoxName, TextBox.TextProperty, binding); 

Vì đường dẫn trong ràng buộc này ("BindingPath") chỉ là một chuỗi, chuỗi đó có thể đến từ bất kỳ đối tượng có sẵn nào.

Bạn sẽ cần phải móc vào việc tạo các mục dữ liệu của mình để đặt các ràng buộc này.


Một khả năng tiếp tục dựa trên ý kiến ​​của bạn:

This blog post vạch ra một cách để tạo một lớp tùy chỉnh ràng buộc bởi kế thừa từ MarkupExtension. Bạn có thể sử dụng điều này làm điểm bắt đầu để đưa đề xuất của tôi vào đánh dấu xaml có thể tái sử dụng cho trường hợp ràng buộc đặc biệt của bạn.


More suy nghĩ:

Được rồi, đây là một vấn đề thú vị, vì vậy tôi đã quyết định dành một ít thời gian nhìn thấy nếu tôi có thể đưa ra một giải pháp làm việc. Tôi xin lỗi trước cho độ dài của các mẫu mã sau ...

Căn giải pháp của tôi trên bài đăng blog tôi liên kết với trên, chúng tôi tạo ra lớp này:

public class IndirectBinder : MarkupExtension 
    { 
     public string IndirectProperty { get; set; } 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      //try to get bound items for our custom work 
      DependencyObject targetObject; 
      DependencyProperty targetProperty; 
      bool status = TryGetTargetItems(serviceProvider, out targetObject, out targetProperty); 

      if (status) 
      { 
       Control targetControl = targetObject as Control; 
       if (targetControl == null) return null; 

       //Find the object to take the binding from 
       object dataContext = targetControl.DataContext; 
       if (dataContext == null) return null; 

       //Reflect out the indirect property and get the value 
       PropertyInfo pi = dataContext.GetType().GetProperty(IndirectProperty); 
       if (pi == null) return null; 

       string realProperty = pi.GetValue(dataContext, null) as string; 
       if (realProperty == null) return null; 

       //Create the binding against the inner property 
       Binding binding = new Binding(realProperty); 
       binding.Mode = BindingMode.TwoWay; 
       BindingOperations.SetBinding(targetObject, targetProperty, binding); 

       //Return the initial value of the binding 
       PropertyInfo realPi = dataContext.GetType().GetProperty(realProperty); 
       if (realPi == null) return null; 

       return realPi.GetValue(dataContext, null); 

      } 

      return null; 

     } 

     protected virtual bool TryGetTargetItems(IServiceProvider provider, out DependencyObject target, out DependencyProperty dp) 
     { 
      target = null; 
      dp = null; 
      if (provider == null) return false; 

      //create a binding and assign it to the target 
      IProvideValueTarget service = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget)); 
      if (service == null) return false; 

      //we need dependency objects/properties 
      target = service.TargetObject as DependencyObject; 
      dp = service.TargetProperty as DependencyProperty; 
      return target != null && dp != null; 
     } 

Bạn có thể sử dụng đánh dấu mới này với theo xaml:

<TextBox Text="{local:IndirectBinder IndirectProperty=FieldValuePath}"/> 

Trường hợp TextBox có thể là bất kỳ lớp nào thừa kế từ kiểm soát và Văn bản có thể là bất kỳ thuộc tính phụ thuộc nào.

Rõ ràng nếu bạn cần phơi bày bất kỳ tùy chọn dữ liệu nào khác (chẳng hạn như một hoặc hai cách liên kết) thì bạn sẽ cần phải thêm các thuộc tính khác vào lớp.

Trong khi đây là một giải pháp phức tạp, một lợi thế mà nó có hơn bằng cách sử dụng bộ chuyển đổi là ràng buộc cuối cùng được tạo là chống lại thuộc tính bên trong thực tế chứ không phải đối tượng. Điều này có nghĩa là nó phản ứng chính xác với các sự kiện PropertyChanged.

+0

tốt, đây là một cách tiếp cận có thể hoạt động, nhưng tôi thực sự muốn có thể tạo Bindings trong XAML, bởi vì tôi đang lập kế hoạch viết có thuộc tính ràng buộc khác nhau tùy thuộc vào trạng thái của dữ liệu cơ bản. Nhưng có thể tôi thực sự có thể cố gắng viết tất cả logic này trong đoạn mã sau ... – arconaut

+0

và bên cạnh đó, nó không chỉ là TextBlock mà tôi đang định chỉ định ràng buộc. Nó được coi là một trình soạn thảo/trình xem cho bất kỳ thuộc tính nào trên bất kỳ đối tượng nào. Tôi nghĩ rằng tôi nên thêm vào bài viết hàng đầu. – arconaut

+0

cảm ơn câu trả lời và cảm ơn liên kết. Tôi sẽ thử điều này ra – arconaut

-1
<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Path=FieldValuePath} /> 
</DataTemplate> 

Phải là phương pháp chính xác.Nếu bạn đang nghe những thay đổi trong FieldValuePath, bạn sẽ cần phải đảm bảo rằng DummyClass kế thừa từ INotifyPropertyChanged và rằng sự kiện đã thay đổi thuộc tính đang được kích hoạt khi FieldValuePath thay đổi.

+0

xin lỗi, nhưng điều này sẽ đặt văn bản bằng với giá trị FieldValuePath. Vì vậy, nếu bạn có dummyObject.FieldValuePath == "Property1" bạn sẽ nhận được TextBlock.Text == "Property1" – arconaut

+0

Trong trường hợp đó, tất cả các thuộc tính của bạn được khai báo là DependencyProperties? Bạn sẽ có thể liên kết với tài sản của nó nếu đó là trường hợp. Điều này có thể giúp ... http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx –

2

tôi sẽ khuyên bạn sử dụng một bộ chuyển đổi:

<DataTemplate DataType={x:Type local:DummyClass}> 
    <TextBlock Text={Binding Converter={StaticResource PropertyNameToValueConverter, ConverterParameter=FieldValuePath}} /> 
</DataTemplate> 

Bộ chuyển đổi sẽ nhận lớp và tên thuộc tính và từ đó nó sẽ trả về giá trị sử dụng phản ánh.

+0

Nhưng nó sẽ trả lại chỉ một lần. – arconaut

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