• [Silverlight]简单实现DataGrid使用CheckBox选择行


    以前写过几个方法实现这个功能,但最终还是选择了不继承DataGrid,所以再重新发布出来。

    先显示最终结果,其中左边是错误的例子,右边才是正确的

    在DataGrid中使用CheckBox选择行时典型的错误就是CheckBox没有Binding到任何属性上,这样的话当拖动滚动条时CheckBox.IsChecked就会乱掉,如Demo中左边那个DataGrid所示。最直观的解决方法是禁用DataGrid的滚动条,或者在绑定的数据上添加一个用于绑定CheckBox的bool属性。
    其实只要在DataGrid.LoadingRow事件中将CheckBox的DataContext设定为另外一个Object,就不需要牺牲DataGrid的高效能,也不需要改变原有数据的结构。最终的实现方法是自定义一个包含DataGrid的DataGridTemplateColumn,而不需要重写DataGrid,这样的坏处就是每次调用需要多写一局代码,如果不想这样就继承DataGrid然后把这句代码写进去。在DataGrid.Columns中加入自定义的Column,然后在代码中关联DataGrid和这个Colum,就完成了:

     <sdk:DataGrid ItemsSource="{Binding}"
                          AutoGenerateColumns
    ="False"
                          Grid.Column
    ="1"
                          x:Name
    ="TestDataGrid">
                <sdk:DataGrid.Columns>
                    <local:DataGridSelectColumn />
                    <sdk:DataGridTextColumn Header="Name"
                                            Binding
    ="{Binding Name}"
                                            Width
    ="*" />
                </sdk:DataGrid.Columns>
            </sdk:DataGrid>
       TestDataGrid.EnableSelect();

    下面是这个DataGridSelectColumn的具体实现。创建一个UserControl然后把它改成DataGridTemplateColumn,这样好处是DataTemplate和Style中的FrameworkElement都可以轻松地获取。

    <sdk:DataGridTemplateColumn xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
                                x:Class
    ="DataGridSelectSample.DataGridSelectColumn"
                                xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                                xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
                                xmlns:d
    ="http://schemas.microsoft.com/expression/blend/2008"
                                xmlns:mc
    ="http://schemas.openxmlformats.org/markup-compatibility/2006"
                                mc:Ignorable
    ="d" 
                                d:DesignHeight
    ="300"
                                d:DesignWidth
    ="400">
        <sdk:DataGridTemplateColumn.HeaderStyle>
            <Style TargetType="ContentControl">
                <Setter Property="ContentTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <CheckBox  Content="Select All"
                                       VerticalContentAlignment
    ="Center"
                                       VerticalAlignment
    ="Center"
                                       Loaded
    ="OnHeaderCheckBoxLoaded"/>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </sdk:DataGridTemplateColumn.HeaderStyle>
        <sdk:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay}"
                          VerticalAlignment
    ="Center"
                          HorizontalAlignment
    ="Center" />
            </DataTemplate>
        </sdk:DataGridTemplateColumn.CellTemplate>
    </sdk:DataGridTemplateColumn>
    public partial class DataGridSelectColumn : DataGridTemplateColumn
        {

            private DataGrid _ownerDataGrid;
            private CheckBox _headerCheckBox;
            private Dictionary<object, MarkObject> _markObjects;

            public event EventHandler SelectedItemChanged;

            public DataGridSelectColumn()
            {
                InitializeComponent();
                IsReadOnly = true;
                _markObjects = new Dictionary<object, MarkObject>();
            }

            public DataGrid OwnerDataGrid
            {
                get { return _ownerDataGrid; }
                set
                {
                    _ownerDataGrid = value;
                    _ownerDataGrid.LoadingRow += OnLoadingRow;
                }
            }

            public void SelecteAll()
            {
                if (_headerCheckBox != null)
                    _headerCheckBox.IsChecked = true;
                SetAllSelectedStates(true);
            }

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

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

            public void SetSelectedItems(IList items)
            {
                if (_ownerDataGrid.ItemsSource == null)
                    return;

                var enu = _ownerDataGrid.ItemsSource.GetEnumerator();
                while (enu.MoveNext())
                {
                    GetMarkObject(enu.Current).IsSelected = items.Contains(enu.Current);
                }
            }

            private void ClearItems()
            {
                var enu = _ownerDataGrid.ItemsSource.GetEnumerator();
                List<object> list = new List<object>();
                while (enu.MoveNext())
                {
                    list.Add(enu.Current);
                }
                List<object> removableObjects = new List<object>();
                foreach (var item in _markObjects)
                {
                    if (list.Contains(item.Key) == false)
                    {
                        removableObjects.Add(item.Key);
                    }
                }
                for (int i = 0; i < removableObjects.Count; i++)
                {
                    _markObjects.Remove(removableObjects[i]);
                }
            }

            private void OnHeaderCheckBoxLoaded(object sender, RoutedEventArgs e)
            {
                _headerCheckBox = sender as CheckBox;
                _headerCheckBox.Loaded -= OnHeaderCheckBoxLoaded;
                _headerCheckBox.Checked += (s2, e2) => SetAllSelectedStates(true);
                _headerCheckBox.Unchecked += (s2, e2) => SetAllSelectedStates(false);
            }

            private void OnLoadingRow(object sender, DataGridRowEventArgs e)
            {
                object dataContext = e.Row.DataContext;
                FrameworkElement element = this.GetCellContent(e.Row);
                element.DataContext = GetMarkObject(dataContext);
            }

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

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

            private MarkObject GetMarkObject(Object obj)
            {
                if (_markObjects.ContainsKey(obj) == false)
                {
                    MarkObject markObject;
                    markObject = new MarkObject();
                    _markObjects.Add(obj, markObject);
                    markObject.PropertyChanged += (s, e) =>
                    {
                        if (e.PropertyName == "IsSelected")
                        {
                            if (SelectedItemChanged != null)
                            {
                                SelectedItemChanged(this, EventArgs.Empty);
                            }
                        }
                    };
                }

                return _markObjects[obj];
            }
        }

    其中MarkObject是一个继承INotifyPropertyChanged的类,包含Selected属性,这样更改IsSelected时可以更新UI。

    最后加上DataGridExtensions 是为了方便调用。


     

    View Code
      public static class DataGridExtensions
        {
            internal static DataGridSelectColumn GetSelectColumn(this DataGrid dataGrid)
            {
                DataGridSelectColumn result = null;
                for (int i = 0; i < dataGrid.Columns.Count; i++)
                {
                    result = dataGrid.Columns[i] as DataGridSelectColumn;
                    if (result != null)
                        break;
                }
                return result;
            }

            public static void EnableSelect(this DataGrid dataGird)
            {
                var column = GetSelectColumn(dataGird);
                column.OwnerDataGrid = dataGird;
            }

            public static void SelectAll(this DataGrid dataGrid)
            {
                DataGridSelectColumn column = GetSelectColumn(dataGrid);
                if (column == null)
                    throw new Exception("No Select Column");
                column.SelecteAll();
            }

            public static void UnselectAll(this DataGrid dataGrid)
            {
                DataGridSelectColumn column = GetSelectColumn(dataGrid);
                if (column == null)
                    throw new Exception("No Select Column");
                column.UnselectAll();
            }

            public static List<T> GetSelectedItems<T>(this DataGrid dataGrid)
            {
                DataGridSelectColumn column = GetSelectColumn(dataGrid);
                if (column == null)
                    throw new Exception("No Select Column");
                return column.GetSelectedItems<T>();
            }

            public static void SetSelectedItems(this DataGrid dataGrid, IList items)
            {
                DataGridSelectColumn column = GetSelectColumn(dataGrid);
                if (column == null)
                    throw new Exception("No Select Column");
                column.SetSelectedItems(items);
            }
        }

    附上完整源码,欢迎指正。

    /Files/dino623/DataGridSelectSample.zip


    作者:dino.c
    出处:http://www.cnblogs.com/dino623/
    说明:欢迎转载并请标明来源和作者。如有错漏请指出,谢谢。
  • 相关阅读:
    python3 crypto winrandom import error
    Flask-Babel 中文支持(zh-CN和zh-Hans-CN)
    pip 安装psycopg的错误
    Aapache status / apache2ctl status 总是403
    为什么你还在用嵌入式的方式来使用mod_wsgi?
    Git中当add错误的时候怎么办?
    Python 内置彩蛋
    本人AI知识体系导航
    本人SW知识体系导航
    SSH密钥对登录的原理和实践
  • 原文地址:https://www.cnblogs.com/dino623/p/2328874.html
Copyright © 2020-2023  润新知