2014-12-15 20 views
7

Tôi đang cố gắng tạo điều khiển người dùng tùy chỉnh, với chức năng tương tự như DataGrid (nhưng DataGrid không phải là tùy chọn phù hợp tại đây).Điều khiển tùy chỉnh với tầng DataContext thành phần con trong bộ sưu tập

Những gì tôi muốn đạt được là một cái gì đó như thế này:

<my:CustomList ItemsSource="{Binding Items}"> 
    <my:CustomList.Columns> 
     <my:Column Width="60" Binding="{Binding MyCustomProperty}" /> 
    </my:CustomList.Columns> 
</my:CustomList> 

nơi Items sẽ đến từ ViewModel (ví dụ) như thế này:

public ObservableCollection<Item> Items { get; set; } 

public class Item 
{ 
    public string MyCustomProperty { get; set; } 
    public string MyAnotherCustomProperty { get; set; } 
} 

Tôi có vấn đề là với ràng buộc để MyCustomProperty.

Nếu tôi kế thừa điều khiển tùy chỉnh của mình từ DataGrid và sử dụng cột của nó, DataContext truyền từ ItemsSource đến Bindings trong cột tốt. Tôi muốn làm tương tự với điều khiển tùy chỉnh của tôi, mà không kế thừa từ DataGrid. Ma thuật đằng sau DataGrid.Columns nhận được bối cảnh từ ItemsSource là gì?

Edit: Hãy để tôi hỏi một cách khác xung quanh về vấn đề này:

Nếu tôi thực hiện tùy chỉnh DataGridColumn

public class MyDataGridColumn : DataGridBoundColumn 
{ 
    private Binding _bindingSubText; 

    public Binding BindingSubText 
    { 
     get 
     { 
      return _bindingSubText; 
     } 
     set 
     { 
      if (_bindingSubText == value) return; 
      var oldBinding = _bindingSubText; 
      _bindingSubText = value; 
      OnBindingChanged(oldBinding, _bindingSubText); 
     } 
    } 

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) 
    { 
     var textTextBlock = new TextBlock(); 
     var bindingText = Binding ?? new Binding(); 
     textTextBlock.SetBinding(TextBlock.TextProperty, bindingText); 

     var textSubTextBlock = new TextBlock(); 
     var bindingSubText = BindingSubText ?? new Binding(); 
     textSubTextBlock.SetBinding(TextBlock.TextProperty, bindingSubText); 

     var stackPanel = new StackPanel() { Orientation = Orientation.Vertical }; 
     stackPanel.Children.Add(textTextBlock); 
     stackPanel.Children.Add(textSubTextBlock); 

     return stackPanel; 
    } 

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) 
    { 
     // I don't want to edit elements 
     return null; 
    } 
} 

và cố gắng sử dụng nó trong XAML như thế này:

<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False"> 
    <DataGrid.Columns> 
     <my:MyDataGridColumn Binding="{Binding MyCustomProperty}" BindingSubText="{Binding MyAnotherCustomProperty}" /> 
    </DataGrid.Columns> 
</DataGrid> 

Binding cho BindingSubText propertywould vẫn còn đi kèm với DataContext của DataGrid của cha mẹ, cung cấp cho tôi Items. MyAnotherCustomProperty sẽ có wigglies trong thiết kế, nhưng nó sẽ làm việc OK thời gian chạy (vì ràng buộc năng động). Vấn đề của tôi là khi ai đó sẽ sử dụng DataGridColumn tùy chỉnh này, anh/cô ấy sẽ cần phải biết rằng, và sẽ có "sai" IntelliSense cho ràng buộc.

Ngữ cảnh cho thuộc tính Ràng buộc của tập dữ liệu DataGridColumn, sao cho IntelliSense hoạt động như mong đợi?

+1

nó xuất phát từ ItemsControl và nó quản lý chúng, từ đó kiểm soát được bạn bắt nguồn? – ZSH

+0

Mỏ có nguồn gốc từ ItemsControl. –

+0

bạn đã xác định như thế nào (tạo thử nghiệm)? – ZSH

Trả lời

-1

Tôi nghĩ, một trong những tổ tiên của DataGrid xử lý điều đó (có thể là ItemsControl). Nếu điều khiển của bạn không có nguồn gốc từ ItemsControl, bạn phải xử lý thủ công (khi thêm một cột mới vào điều khiển của bạn thiết lập bối cảnh dữ liệu của nó một cách rõ ràng).

Bây giờ tôi thấy điều khiển của bạn cũng có nguồn gốc từ ItemsControl. Sau đó, tôi đề nghị xử lý nó bằng tay.

2

Câu hỏi của bạn thực sự rộng nhưng trước hết nếu bạn muốn mở rộng DataGrid, hãy xem xét ghi đè kiểu của nó và thêm trình kích hoạt hoặc thứ gì đó tương tự.

Đó là vấn đề trong thiết kế của bạn .. và khó có thể biết được điều gì đúng hay sai ở đây.

Thuộc tính cột trong DataGrid và trong GridView nhiều hay ít chỉ là một đối tượng giả giữ giá trị mà các ô sau sẽ cần ví dụ: mẫu ô, ràng buộc, chiều rộng, chiều cao ... v.v. Giả sử như cột này không có true DataContext ...

DataContext được chuyển xuống cây hình ảnh/lôgic funcional nhưng thuộc tính cột không có ở đó. Đó là lý do tại sao bạn có vấn đề của bạn. Tất cả các ràng buộc mà bạn có thể thiết lập trong một đối tượng cột như vậy thực sự là nơi giữ. Tuy nhiên các tế bào tham gia vào cây thị giác, vì chúng là một điều khiển riêng, và vì vậy một khi một tế bào được tạo ra, chúng làm những thứ như thế này trước khi chúng được rút ra: cellTextBlock.SetBinding (TextBlock.TextProperty, columnBindingPlaceHolder), cellTextBlock.SetBinding (TextBlock. HeightProperty, columnHeightPlaceHolder).

tế bào sử dụng những placeholders từ cột

Nếu bạn muốn tuy nhiên với tài sản cột tùy chỉnh của riêng bạn để có cùng một DataContext như DataGrid xem xét thay đổi ObseravableCollection để FreezableCollection. Cũng làm cho đối tượng Column là một đối tượng Freezable. Chỉ cần làm việc với Freezables. Bởi vì trong WPF chúng có khả năng kế thừa DataContext. Brushes trong Wpf là freezables chẳng hạn.

Hy vọng điều này sẽ giúp bạn nhiều hơn nữa.

+1

Tuy nhiên, một trong những (sẽ hợp lý?) Mong đợi rằng một tài sản trên một Visual/Phần tử cây logic sẽ nhận được sự trợ giúp của DataContext từ công cụ. Có lẽ vấn đề là trong công cụ ... Từ những gì bạn nói nó sẽ ám chỉ như vậy, hoặc tôi có sai không? –

+0

Tôi đã thử với freezables, nhưng không có gần gũi hơn với các giải pháp. Dù sao, cảm ơn vì đã giúp đỡ. Tôi đoán bạn kiếm được tiền thưởng :) –

+0

Xin lỗi người đàn ông, tôi đã bận rộn ăn công cụ, kết hôn với Xmas btw :) đây là một bài viết tuyệt vời về freezable http://joshsmithonwpf.wordpress.com/2008/07/22/enable-elementname- bindings-with-elementspy/ josh smith biết rất nhiều về wpf, anh ta tạo ra một elementpy là một lớp kế thừa từ freezable –

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