2013-06-29 39 views
6

Tôi đang cố gắng tạo cột hộp kiểm của riêng mình (thay thế cột mặc định), để chuyển sang cột dữ liệu phức tạp sau này và tôi có mã sau:WPF DataGrid - Tạo cột tùy chỉnh mới

public class MyCheckBoxColumn : DataGridBoundColumn 
{ 
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) 
    { 
     var cb = new CheckBox(); 
     var bb = this.Binding as Binding; 
     var b = new Binding { Path = bb.Path, Source = cell.DataContext }; 
     cb.SetBinding(ToggleButton.IsCheckedProperty, b); 
     return cb; 
    } 

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) 
    { 
     var cb = new CheckBox(); 
     var bb = this.Binding as Binding; 
     var b = new Binding { Path = bb.Path, Source = ToggleButton.IsCheckedProperty }; 
     cb.SetBinding(ToggleButton.IsCheckedProperty, b); 
     return cb; 
    } 

    protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs) 
    { 
     var cb = editingElement as CheckBox; 
     return cb.IsChecked; 
    } 

    protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue) 
    { 
     var cb = editingElement as CheckBox; 
     if (cb != null) cb.IsChecked = (bool)uneditedValue; 
    } 

    protected override bool CommitCellEdit(FrameworkElement editingElement) 
    { 
     var cb = editingElement as CheckBox; 
     BindingExpression binding = editingElement.GetBindingExpression(ToggleButton.IsCheckedProperty); 
     if (binding != null) binding.UpdateSource(); 
     return true;// base.CommitCellEdit(editingElement); 
    } 
} 

Và DataGrid tùy chỉnh của tôi:

public class MyDataGrid : DataGrid 
{ 
    protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e) 
    { 
     try 
     { 
      var type = e.PropertyType; 
      if (type == typeof(bool)) 
      { 
       var col = new MyCheckBoxColumn(); 
       col.Binding = new Binding(e.PropertyName) {Mode = BindingMode.TwoWay}; 
       e.Column = col; 
      } 
      else 
      { 
       base.OnAutoGeneratingColumn(e); 
      } 
      var propDescr = e.PropertyDescriptor as System.ComponentModel.PropertyDescriptor; 
      e.Column.Header = propDescr.Description; 
     } 
     catch (Exception ex) 
     { 
      Utils.ReportException(ex); 
     } 
    } 
} 

Bây giờ, tất cả mọi thứ có vẻ tốt đẹp ngoại trừ hai điều:

  • dường như t anh ta chỉ sử dụng phương pháp trong số MyCheckBoxColumnGenerateElement(). Tất cả các phương pháp khác không được sử dụng. Tôi đã đặt điểm ngắt trong họ và họ không bao giờ bị trúng ...
  • Tôi sử dụng ObservableCollection làm nguồn dữ liệu và phần còn lại của các cột thông báo cho tôi khi chúng được thay đổi.

Điều kỳ lạ là giá trị bool bị thay đổi khi bạn chọn/bỏ chọn hộp kiểm, nhưng không thông báo và không đi qua CommitCellEdit(). Có ai biết điều gì đang xảy ra ở đây không?

EDIT:

Dường như nếu tôi trả lại một TextBlock từ bên GenerateElement() nó làm cho các phương pháp khác để được gọi là (vấn đề thông báo không được cố định mặc dù). Nhưng tại sao điều này không làm việc với CheckBox? Cột hộp kiểm tra mặc định hoạt động như thế nào ???

Trả lời

4

OK. Đây là mã hoàn chỉnh cho cột Hộp kiểm tùy chỉnh. Có vẻ như, để có một điều khiển như một hộp kiểm như một phần tử hiển thị (không chỉnh sửa) trong một DataGrid, bạn phải làm cho nó trở thành hit-test-invisible. Hoặc bạn có thể chỉ cần sử dụng TextBlock để hiển thị một số ký tự giống như dấu kiểm:

public class MyCheckBoxColumn : DataGridBoundColumn 
{ 
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) 
    { 
     var cb = new CheckBox() { IsHitTestVisible = false, HorizontalAlignment = HorizontalAlignment.Center, HorizontalContentAlignment = HorizontalAlignment.Center }; 
     var bb = this.Binding as Binding; 
     var b = new Binding { Path = bb.Path, Source = dataItem, Mode = BindingMode.TwoWay }; 
     cb.SetBinding(ToggleButton.IsCheckedProperty, b); 
     return cb; 
//   var cb = new TextBlock() { TextAlignment = TextAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center }; 
//   var bb = this.Binding as Binding; 
//   var b = new Binding { Path = bb.Path, Source = dataItem, Mode = BindingMode.TwoWay, Converter = new MyBoolToMarkConverter() }; 
//   cb.SetBinding(TextBlock.TextProperty, b); 
//   return cb; 
    } 

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) 
    { 
     var cb = new CheckBox() { HorizontalAlignment = HorizontalAlignment.Center, HorizontalContentAlignment = HorizontalAlignment.Center }; 
     var bb = this.Binding as Binding; 
     var b = new Binding { Path = bb.Path, Source = dataItem, Mode = BindingMode.TwoWay }; 
     cb.SetBinding(ToggleButton.IsCheckedProperty, b); 
     return cb; 
    } 

    protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs) 
    { 
     var cb = editingElement as CheckBox; 
     if (cb != null) return cb.IsChecked; 
     return false; 
    } 

    protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue) 
    { 
     var cb = editingElement as CheckBox; 
     if (cb != null) cb.IsChecked = (bool)uneditedValue; 
    } 

    protected override bool CommitCellEdit(FrameworkElement editingElement) 
    { 
     // The following 2 lines seem to help when sometimes the commit doesn't happen (for unknown to me reasons). 
     //var cb = editingElement as CheckBox; 
     //cb.IsChecked = cb.IsChecked; 
     BindingExpression binding = editingElement.GetBindingExpression(ToggleButton.IsCheckedProperty); 
     if (binding != null) binding.UpdateSource(); 
     return true;// base.CommitCellEdit(editingElement); 
    } 
} 
//-------------------------------------------------------------------------------------------- 
public class MyBoolToMarkConverter : IValueConverter 
{ 
    const string cTick = "■"; 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value.GetType() != typeof(bool)) return ""; 
     bool val = (bool)value; 
     return val ? cTick : ""; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value.GetType() != typeof(string)) return false; 
     string val = (string)value; 
     return val == cTick; 
    } 
} 
//-------------------------------------------------------------------------------------------- 
+0

Tôi không biết tại sao không ai trả lời câu hỏi của tôi. Có phải vì WPF được cho là bị bỏ rơi bởi M $ và bạn không quan tâm đến nó nữa? Có phải bạn không biết câu trả lời? Dù sao, WinForms, và nhiều hơn nữa đã được coi là công nghệ bị bỏ rơi và họ vẫn còn được sử dụng ngày nay. M $ chỉ muốn thúc đẩy các nhà phát triển quảng cáo đồ chơi điện thoại di động của họ. – NoOne

+2

Tôi sẽ không nói rằng WPF bị bỏ rơi, nhưng tôi hy vọng nhiều người không đào sâu này vào tác giả kiểm soát. –

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