本文介绍了WPF DataGrid - 创建一个新的自定义列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建自己的复选框列(替换默认值),以便稍后移动到更复杂的数据列,我有以下代码:

I am trying to create my own checkbox column (replacing the default one), in order to move to more complex data columns later-on, and I have the following code:

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);
    }
}

我的自定义DataGrid:

And my custom DataGrid:

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);
        }
    }
}

现在,除了有两件事:


  • 似乎在 MyCheckBoxColumn 中唯一使用的方法是GenerateElement() 所有其他方法都不使用。我已经把断点放在了他们里面,他们从来没有受到打击...

  • 我使用 ObservableCollection 作为数据源,而其余的列通知我什么时候改变,这个没有。

  • It seems that the only used method in in MyCheckBoxColumn is the GenerateElement(). All the other methods are not used. I have put breakpoints in them and they never get hit...
  • I use an ObservableCollection as a data source and, while the rest of the columns notify me when they get changed, this one doesn't.

奇怪的是,<$ c $检查/取消选中复选框,但不通知,而不通过 CommitCellEdit(),c> bool 值会更改。
有没有人知道这里出了什么问题?

The odd thing is that the bool value gets changed when you check/uncheck the checkbox, but without notification and without passing through CommitCellEdit().Does anyone know what is going wrong here?

编辑

似乎如果我从 GenerateElement()里面返回一个 TextBlock ,它会使其他方法被调用通知问题没有得到修复)。但是为什么这不能与CheckBoxes配合使用?默认复选框列如何工作?

It seems that if I return a TextBlock from inside GenerateElement() it makes the other methods to be called (the notification problem doesn't get fixed though). But why doesn't this work with with CheckBoxes? How does the default check box column work???

推荐答案

确定。以下是自定义复选框列的完整代码。看来,为了让一个控件像一个复选框作为DataGrid中的一个显示(不编辑)元素,你必须使它不受测试 - 不可见。或者您可以使用TextBlock显示一些类似于复选标记的字符:

OK. Here is the complete code for a custom CheckBox column. It seems that, in order to have a control like a checkbox as a display (not editing) element in a DataGrid you have to make it hit-test-invisible. Or you can simply use a TextBlock to display some character that resembles a checkmark:

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;
    }
}
//--------------------------------------------------------------------------------------------

这篇关于WPF DataGrid - 创建一个新的自定义列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 02:59