DevExpress GridControl keep the selection of detail grid after collapse

问题:DevExpress gridview设置为master-detail模式,当选中detail gridview中的行后,收缩master gridview,然后再展开时,detail gridview行选中状态未保存。

解决:

18.1版本以上可以通过设置GridView的OptionSelection中CheckBoxSelectorField
属性。

18.1版本以下可以通过以下代码实现,实现group/master上下级联勾选、detail选中状态保存

multiple-selection-using-checkbox-in-a-master-detail-grid-e3507

效果图:

 

其中主要代码如下:

GridCheckMarksSelection类

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using DevExpress.Utils.Drawing;
using System.Data;
using E1271;
using System.Collections.Generic;
using DevExpress.XtraEditors.ViewInfo;
using DevExpress.XtraEditors.Drawing;
using System.Linq;

namespace DevExpress.XtraGrid.Selection {

    public class GridCheckMarksSelection {
        public const string CHECKMARK_FIELDNAME = "CheckMarkSelection";
        GridView _view;
        GridView _parentView;
        ArrayList selection;
        GridColumn column;
        RepositoryItemCheckEdit edit;
        Dictionary<DetailKey, GridCheckMarksSelection> detailSelections = new Dictionary<DetailKey, GridCheckMarksSelection>();
        GridCheckMarksSelection parentSelection = null;
        const int CheckboxIndent = 4;
        public GridCheckMarksSelection() {
            selection = new ArrayList();
        }
        public GridCheckMarksSelection(GridView view, GridCheckMarksSelection parentCheckMarkSelection) : this() {
            View = view;
            parentSelection = parentCheckMarkSelection;
            _parentView = parentSelection.View;
        }
        public GridCheckMarksSelection(GridView view) : this() {
            View = view;
        }
        public GridView View {
            get { return _view; }
            set {
                if (_view != value) {
                    Detach(value);
                    Attach(value);
                }
            }
        }
        public GridColumn CheckMarkColumn { get { return column; } }
        public int SelectedCount { get { return selection.Count; } }
        public bool IsMasterView {
            get { return _parentView == null; }
        }

        #region Attach / Detach
        void AddCheckColumn() {
            edit = View.GridControl.RepositoryItems["CheckMark"] as RepositoryItemCheckEdit;
            if (edit == null) {
                edit = View.GridControl.RepositoryItems.Add("CheckEdit") as RepositoryItemCheckEdit;
                edit.Name = "CheckMark";
            }
            column = View.Columns.Add();
            column.OptionsColumn.AllowSort = DevExpress.Utils.DefaultBoolean.False;
            column.Visible = true;
            column.VisibleIndex = 0;
            column.FieldName = CHECKMARK_FIELDNAME;
            column.Caption = "Mark";
            column.OptionsColumn.ShowCaption = false;
            column.OptionsColumn.AllowEdit = false;
            column.OptionsColumn.AllowSize = false;
            column.UnboundType = DevExpress.Data.UnboundColumnType.Boolean;
            column.Width = GetCheckBoxWidth();
            column.ColumnEdit = edit;
        }
        void SubscribeViewToEvents() {
            View.Click += new EventHandler(View_Click);
            View.CustomDrawColumnHeader += new ColumnHeaderCustomDrawEventHandler(View_CustomDrawColumnHeader);
            View.CustomDrawGroupRow += new RowObjectCustomDrawEventHandler(View_CustomDrawGroupRow);
            View.CustomUnboundColumnData += new CustomColumnDataEventHandler(view_CustomUnboundColumnData);
            View.KeyDown += new KeyEventHandler(view_KeyDown);
            View.RowStyle += new RowStyleEventHandler(view_RowStyle);
            View.MasterRowExpanded += view_MasterRowExpanded;
        }
        void UnsubscribeViewFromEvents() {
            View.Click -= View_Click;
            View.CustomDrawColumnHeader -= View_CustomDrawColumnHeader;
            View.CustomDrawGroupRow -= View_CustomDrawGroupRow;
            View.CustomUnboundColumnData -= view_CustomUnboundColumnData;
            View.KeyDown -= view_KeyDown;
            View.RowStyle -= view_RowStyle;
            View.MasterRowExpanded -= view_MasterRowExpanded;
        }
        protected virtual void Attach(GridView view) {
            if (view == null) return;
            _view = view;
            AddCheckColumn();
            SubscribeViewToEvents();
        }
        protected virtual void Detach(GridView newView) {
            newView.Columns.Remove(newView.Columns[CHECKMARK_FIELDNAME]);
            if (_view == null) return;
            UnsubscribeViewFromEvents();
            _view = null;
        }
        #endregion

        public object GetSelectedRow(int index) {
            return selection[index];
        }
        public int GetSelectedIndex(object row) {
            foreach (object record in selection)
                if ((record as DataRowView).Row == (row as DataRowView).Row)
                    return selection.IndexOf(record);
            return selection.IndexOf(row);
        }

        #region Selection Methods
        
        public void SelectRow(int rowHandle, bool select) {
            if (View.IsGroupRow(rowHandle)) {
                SelectGroup(rowHandle, select);
                return;
            }
            SelectRow(rowHandle, select, true);
        }
        public void SelectRowObject(object row, bool select) {
            int rowHandle = View.GetRowHandle(((IList)View.DataSource).IndexOf(row));
            SelectRow(rowHandle, select, true);
        }
        public void ClearSelection() {
            selection.Clear();
            UpdateParentAndDetailSelection(false);
            InvalidateView();
        }
        public void SelectAll() {
            selection.Clear();
            selection.AddRange((IList)View.DataSource);
            UpdateParentAndDetailSelection(true);
            InvalidateView();
        }
        public void InvertDetailRowsSelection(int masterRowHandle) {
            GetDetailSelectionHelper(masterRowHandle, 0).SetAllDetailsSelected(masterRowHandle, IsRowSelected(masterRowHandle));
        }
        public void InvertRowSelection(int rowHandle) {
            if (View.IsDataRow(rowHandle))
                SelectRow(rowHandle, !IsRowSelected(rowHandle));
            if (View.IsGroupRow(rowHandle))
                SelectGroup(rowHandle, !IsGroupRowSelected(rowHandle));
        }
        void SelectRow(int rowHandle, bool select, bool invalidate) {
            if (IsRowSelected(rowHandle) == select) return;
            object row = View.GetRow(rowHandle);
            if (select)
                selection.Add(row);
            else
                selection.RemoveAt(GetSelectedIndex(row));
            if (IsMasterView)
                SetAllDetailsSelected(rowHandle, select);
            else
                SetParentRowSelected(AreAllDetailsSelected());
            if (invalidate)
                InvalidateView();
        }
        void SelectGroup(int rowHandle, bool select) {
            if (IsGroupRowSelected(rowHandle) && select) return;
            for (int i = 0; i < View.GetChildRowCount(rowHandle); i++) {
                int childRowHandle = View.GetChildRowHandle(rowHandle, i);
                if (View.IsGroupRow(childRowHandle))
                    SelectGroup(childRowHandle, select);
                else
                    SelectRow(childRowHandle, select, false);
            }
            InvalidateView();
        }
        void SetParentRowSelected(bool selected) {
            if (selected)
                parentSelection.selection.Add(View.SourceRow);
            else
                parentSelection.selection.Remove(View.SourceRow);
            _parentView.LayoutChanged();
        }
        void UpdateParentAndDetailSelection(bool select) {
            if (IsMasterView)
                for (int i = 0; i < View.DataRowCount; i++)
                    SetAllDetailsSelected(i, select);
            else
                SetParentRowSelected(AreAllDetailsSelected());
        }
        void SetAllDetailsSelected(int masterRowHandle, bool select) {
            int relationCount = View.GetRelationCount(masterRowHandle);
            for (int i = 0; i < relationCount; i++)
                SetAllDetailRowsSelected(masterRowHandle, i, select);    
        }
        void SetAllDetailRowsSelected(int masterRowHandle, int relationIndex, bool select) {
            GridCheckMarksSelection detailSelectionHelper = GetDetailSelectionHelper(masterRowHandle, relationIndex);
            detailSelectionHelper.selection.Clear();
            if (select)
                detailSelectionHelper.selection.AddRange(View.DataController.GetDetailList(masterRowHandle, relationIndex));
            if (detailSelectionHelper.View != null) detailSelectionHelper.View.LayoutChanged();
        }
        #endregion

        GridCheckMarksSelection GetDetailSelectionHelper(int masterRowHandle, int relationIndex) {
            DetailKey key = new DetailKey(masterRowHandle, relationIndex);
            if (!detailSelections.ContainsKey(key))
                detailSelections.Add(key, new GridCheckMarksSelection(null, this));
            return detailSelections[key];
        }
        bool AreAllRowsSelected() {
            if (View != null)
                return SelectedCount == View.DataRowCount;
            else {
                DetailKey key = parentSelection.detailSelections.FirstOrDefault(x => x.Value == this).Key;
                return SelectedCount == _parentView.DataController.GetDetailList(key.MasterRowHandle, key.RelationIndex).Count;
            }
        }
        bool AreAllDetailsSelected() { // call it for a detail helper
            int relationCount = _parentView.GetRelationCount(View.SourceRowHandle);
            for (int i = 0; i < relationCount; i++){
                if (!parentSelection.GetDetailSelectionHelper(View.SourceRowHandle, i).AreAllRowsSelected())
                    return false;
            }
            return true;
        }
        bool IsGroupRowSelected(int rowHandle) {
            for (int i = 0; i < View.GetChildRowCount(rowHandle); i++) {
                int childRowHandle = View.GetChildRowHandle(rowHandle, i);
                if (View.IsGroupRow(childRowHandle)) {
                    if (!IsGroupRowSelected(childRowHandle)) return false;
                } else
                    if (!IsRowSelected(childRowHandle)) return false;
            }
            return true;
        }
        public bool IsRowSelected(int rowHandle) {
            if (View.IsGroupRow(rowHandle))
                return IsGroupRowSelected(rowHandle);
            object row = View.GetRow(rowHandle);
            return IsObjectSelected(row);
        }
        public bool IsObjectSelected(object row) {
            return GetSelectedIndex(row) != -1;
        }
        protected int GetCheckBoxWidth() {
            CheckEditViewInfo info = edit.CreateViewInfo() as CheckEditViewInfo;
            int width = 0;
            GraphicsInfo.Default.AddGraphics(null);
            try {
                width = info.CalcBestFit(GraphicsInfo.Default.Graphics).Width;
            }
            finally {
                GraphicsInfo.Default.ReleaseGraphics();
            }
            return width + CheckboxIndent * 2;
        }
        void InvalidateView() {
            View.CloseEditor();
            View.BeginUpdate();
            View.EndUpdate();
        }

        #region Events
        void view_MasterRowExpanded(object sender, CustomMasterRowEventArgs e) {
            GridView detailView = View.GetDetailView(e.RowHandle, e.RelationIndex) as GridView;
            GridCheckMarksSelection detailHelper = GetDetailSelectionHelper(e.RowHandle, e.RelationIndex);
            detailHelper.View = detailView;
            detailHelper.View.LayoutChanged();
        }
        void view_CustomUnboundColumnData(object sender, CustomColumnDataEventArgs e) {
            if (e.Column == CheckMarkColumn) {
                if (e.IsGetData)
                    e.Value = IsObjectSelected(e.Row);
                else
                    SelectRowObject(e.Row, (bool)e.Value);
            }
        }
        void view_KeyDown(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.Space && (View.FocusedColumn == CheckMarkColumn || View.IsGroupRow(View.FocusedRowHandle)))
                InvertRowSelection(View.FocusedRowHandle);
        }
        void View_Click(object sender, EventArgs e) {
            Point pt = View.GridControl.PointToClient(Control.MousePosition);
            GridHitInfo info = View.CalcHitInfo(pt);
            if (info.InColumn)
                if (AreAllRowsSelected())
                    ClearSelection();
                else
                    SelectAll();
            if (info.InRow && info.HitTest != GridHitTest.RowGroupButton && info.HitTest !=  GridHitTest.CellButton)
                InvertRowSelection(info.RowHandle);
        }
        #endregion

        #region Painting

        protected void DrawCheckBox(Graphics g, Rectangle r, bool _checked) {
            CheckEditViewInfo info = edit.CreateViewInfo() as CheckEditViewInfo;
            CheckEditPainter painter = edit.CreatePainter() as CheckEditPainter;
            info.EditValue = _checked;
            info.Bounds = r;
            info.CalcViewInfo(g);
            ControlGraphicsInfoArgs args = new ControlGraphicsInfoArgs(info, new GraphicsCache(g), r);
            painter.Draw(args);
            args.Cache.Dispose();
        }
        void View_CustomDrawColumnHeader(object sender, ColumnHeaderCustomDrawEventArgs e) {
            if (e.Column != null && e.Column == column) {
                e.Info.InnerElements.Clear();
                e.Painter.DrawObject(e.Info);
                DrawCheckBox(e.Cache.Graphics, e.Bounds, AreAllRowsSelected());
                e.Handled = true;
            }
        }
        void View_CustomDrawGroupRow(object sender, RowObjectCustomDrawEventArgs e) {
            GridGroupRowInfo info = e.Info as GridGroupRowInfo;
            info.GroupText = "         " + info.GroupText.TrimStart();
            e.Info.Paint.FillRectangle(e.Cache.Graphics, e.Appearance.GetBackBrush(e.Cache), e.Bounds);
            e.Painter.DrawObject(e.Info);
            Rectangle r = info.ButtonBounds;
            r.Offset(r.Width + CheckboxIndent * 2 - 1, 0);
            DrawCheckBox(e.Cache.Graphics, r, IsGroupRowSelected(e.RowHandle));
            e.Handled = true;
        }
        void view_RowStyle(object sender, RowStyleEventArgs e) {
            if (IsRowSelected(e.RowHandle))
            {
                e.Appearance.BackColor = SystemColors.Highlight;
                e.Appearance.ForeColor = SystemColors.HighlightText;
            }
        }
        #endregion
    }
}

DetailKey类

using System;
using System.Collections.Generic;
using System.Linq;

namespace E1271
{
    public class DetailKey {
        public DetailKey(int _masterRowHandle, int _relationIndex) {
            MasterRowHandle = _masterRowHandle;
            RelationIndex = _relationIndex;
        }
        public int MasterRowHandle { get;set; }
        public int RelationIndex { get;set; }
        public override int GetHashCode() {
            return MasterRowHandle.GetHashCode() ^ RelationIndex.GetHashCode();
        }
        public override bool Equals(object obj) {
            if (obj is DetailKey)
                return ((DetailKey)obj).MasterRowHandle == MasterRowHandle && ((DetailKey)obj).RelationIndex == RelationIndex;
            return base.Equals(obj);
        }
    }
}

调用示例:

new GridCheckMarksSelection(gridView1);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值