zoukankan      html  css  js  c++  java
  • DataGrid中动态添加列,使用CheckBox选择行

    在DataGrid中使用CheckBox选择行时典型的错误就是CheckBox没有Binding到任何属性上,这样的话当拖动滚动条时CheckBox.IsChecked就会乱掉,如Demo中左边那个DataGrid所示。最直观的解决方法是禁用DataGrid的滚动条,或者在绑定的数据上添加一个用于绑定CheckBox的bool属性。
    其实只要在DataGrid.LoadingRow事件中将CheckBox的DataContext设定为另外一个Object,就不需要牺牲DataGrid的高效能,也不需要改变原有数据的结构。具体实现如下:

     

    <my:MyDataGrid ItemsSource="{Binding}"
    AutoGenerateColumns="False">
    <my:MyDataGrid.Columns>
    <sdk:DataGridTextColumn Header="Name"
    Binding="{Binding Name}"
    Width="*" />
    <sdk:DataGridTextColumn Header="GUID"
    Binding="{Binding GUID}"
    Width="*" />
    </my:MyDataGrid.Columns>
    </my:MyDataGrid>

     

    public class MyDataGrid : DataGrid
    {
    private const string HeaderCheckBoxName = "select_column_checkbox";

    private Dictionary<object, MarkObject> _markObjects;
    private DataGridTemplateColumn _selectColumn;
    private CheckBox _selectCheckBox;

    public MyDataGrid()
    {
    _markObjects = new Dictionary<object, MarkObject>();

    _selectColumn = new DataGridTemplateColumn();
    _selectColumn.HeaderStyle = GetHeaderStyle();
    _selectColumn.CellTemplate = GetCellTemplate();
    this.Columns.Insert(0, _selectColumn);
    this.SizeChanged += new SizeChangedEventHandler(OnSizeChanged);
    }

    public void SelectAll()
    {
    if (_selectCheckBox != null)
    _selectCheckBox.IsChecked = true;
    SetAllSelectedStates(true);
    }

    public void UnselectAll()
    {
    if (_selectCheckBox != null)
    _selectCheckBox.IsChecked = false;
    SetAllSelectedStates(false);
    }

    public List<T> GetSelectedItems<T>()
    {
    List<T> result = new List<T>();
    if (ItemsSource != null)
    {
    var enu = ItemsSource.GetEnumerator();
    while (enu.MoveNext())
    {
    if (GetMarkObject(enu.Current).Selected)
    result.Add((T)enu.Current);
    }
    }
    return result;
    }

    protected override void OnLoadingRow(DataGridRowEventArgs e)
    {
    base.OnLoadingRow(e);

    object dataContext = e.Row.DataContext;
    FrameworkElement element = _selectColumn.GetCellContent(e.Row);
    element.DataContext = GetMarkObject(dataContext);
    }

    private Style GetHeaderStyle()
    {
    Style style = new System.Windows.Style();
    style.TargetType = typeof(ContentControl);

    StringBuilder tmp = new StringBuilder();
    tmp.Append("<DataTemplate ");
    tmp.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
    tmp.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >");
    tmp.Append(string.Format("<CheckBox Content='Select All' x:Name='{0}' VerticalAlignment='Center' HorizontalAlignment='Center' />", HeaderCheckBoxName));
    tmp.Append("</DataTemplate>");
    DataTemplate contentTemplate = XamlReader.Load(tmp.ToString()) as DataTemplate;

    style.Setters.Add(new Setter(ContentControl.ContentTemplateProperty, contentTemplate));
    return style;
    }

    private DataTemplate GetCellTemplate()
    {
    StringBuilder tmp = new StringBuilder();
    tmp.Append("<DataTemplate ");
    tmp.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
    tmp.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' >");
    tmp.Append("<CheckBox IsChecked='{Binding Selected,Mode=TwoWay}' VerticalAlignment='Center' HorizontalAlignment='Center' />");
    tmp.Append("</DataTemplate>");
    return XamlReader.Load(tmp.ToString()) as DataTemplate;
    }

    private MarkObject GetMarkObject(Object obj)
    {
    if (_markObjects.ContainsKey(obj) == false)
    {
    MarkObject markObject;
    markObject = new MarkObject();
    _markObjects.Add(obj, markObject);
    }

    return _markObjects[obj];
    }

    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
    _selectCheckBox = this.GetChild<CheckBox>(HeaderCheckBoxName);
    if (_selectCheckBox == null)
    return;

    _selectCheckBox.Checked += (sender2, e2) => SetAllSelectedStates(true);
    _selectCheckBox.Unchecked += (sender2, e2) => SetAllSelectedStates(false);
    }

    private void SetAllSelectedStates(bool value)
    {
    if (ItemsSource == null)
    return;

    var enu = ItemsSource.GetEnumerator();
    while (enu.MoveNext())
    {
    GetMarkObject(enu.Current).Selected = value;
    }
    }




    }

    其中MarkObject是一个继承INotifyPropertyChanged的类,包含Selected属性,这样更改Selected时可以更新UI。在构造函数中直接插入了个模板列,模板列使用XamlReader.Load(string str)方法直接在代码中创建模板。至于列头的CheckBox则在SizeChanged事件时才可以通过VisualTreeHelper.GetChild递归找到。

     

    原文:http://www.cyqdata.com/cnblogs/article-detail-25516上面有效果图,效果图怎么实现的

     

     

  • 相关阅读:
    poj3686 Windys
    poj3155 Hard Life
    luoguP2774 方格取数问题
    poj3469 Dual Core CPU
    poj3281 Dining
    luogu P3410 拍照
    离散化
    最短路(SPFA)
    lower_bound && upper_bound
    gcd
  • 原文地址:https://www.cnblogs.com/whpepsi/p/2363120.html
Copyright © 2011-2022 走看看