Devexpress 更改数据源时,DevXPress XtraGrid聚焦于已更改的事件问题

Devexpress 更改数据源时,DevXPress XtraGrid聚焦于已更改的事件问题,devexpress,xtragrid,Devexpress,Xtragrid,这个问题困扰了我好几年,也许这里有人知道一个简单的解决方案,因为我又遇到了 问题:在将新的(不同的)数据源分配给网格之前,有没有办法让XtraGrid“忘记”当前关注的行索引 背景 我们使用XtraGrid作为一种控制器,用于多面板Winform的另一个面板中显示的内容 现在想象一个假设场景,其中XtraGrid的数据源根据菜单选择不断变化。菜单项1用自助餐厅中今天的主菜列表填充网格:Id,Name。菜单项2使用用户当天必须致电的客户列表填充网格:ID、姓名。重要的是,这些数据源是不同的,网格的

这个问题困扰了我好几年,也许这里有人知道一个简单的解决方案,因为我又遇到了

问题:在将新的(不同的)数据源分配给网格之前,有没有办法让XtraGrid“忘记”当前关注的行索引

背景 我们使用XtraGrid作为一种控制器,用于多面板Winform的另一个面板中显示的内容

现在想象一个假设场景,其中XtraGrid的数据源根据菜单选择不断变化。菜单项1用自助餐厅中今天的主菜列表填充网格:Id,Name。菜单项2使用用户当天必须致电的客户列表填充网格:ID、姓名。重要的是,这些数据源是不同的,网格的数据源正在被分配和重新分配

这一问题的关键事实: 我们希望网格的FocusedRowChanged事件是我们在控制器网格中捕获用户选择的单个位置。我们是一家“无意大利面代码”商店。FocusedRowChanged比单击事件更好,因为它也处理键盘导航。具有焦点的行包含我们需要从数据库中获取以显示在面板2中的详细记录的ID。大多数情况下,这是有效的

下面是它的工作原理:假设在给定的一天,用户必须联系的客户列表只包含一行。因此,网格中的第一行(也是唯一一行)是聚焦行。现在让我们假设用户进入菜单并选择菜单项以显示当天的自助餐厅主菜。当用户单击entres列表中的第一项时,不会触发FocusedRowChanged事件,因为网格保留了来自上一个数据源的聚焦行索引的内存。焦点行索引未更改。因此,用户的选择不会触发任何事件

我试图让DevExpress提供第二种面向行的模式(不同于面向行索引的方法),即网格中的每一行都有一个GUID,并且只要当前关注行的GUID与以前关注行的GUID不同,就会触发FocusedRowChanged事件,不管聚焦行索引是否恰好相同。这将允许动态更改数据源并启用所需的行为。但他们表示反对


所以我要再次问我的问题,有没有办法让XtraGrid在将新数据源分配给网格之前“忘记”当前的焦点行索引?

我认为解决这个问题的最佳方法是创建一个新的GridView对象并覆盖其DoChangeFocusedRowInternal方法。下面您将找到此方法的默认实现。您所需要做的就是根据需要更改标记行。另外,看看这篇文章,它包含了一些有用的信息

public class MyGridView : GridView {
        protected override void DoChangeFocusedRowInternal(int newRowHandle, bool updateCurrentRow) {
            if(this.lockFocusedRowChange != 0) return;
            if(!IsValidRowHandle(newRowHandle))
                newRowHandle = DevExpress.Data.DataController.InvalidRow;
            if(FocusedRowHandle == newRowHandle) return; // <<<<<<
            int currentRowHandle = FocusedRowHandle;
            BeginLockFocusedRowChange();
            try {
                DoChangeFocusedRow(FocusedRowHandle, newRowHandle, updateCurrentRow);
            }
            finally {
                EndLockFocusedRowChange();
            }
            RaiseFocusedRowChanged(currentRowHandle, newRowHandle);
        }
    }

Tim,当网格中只有一行数据,然后更改了数据源时,我遇到了完全相同的问题。在设置新数据源后,我通过设置gridview.FocusedRowHandle=-1解决了这个问题

您可以订阅DataSourceChanged事件,该事件将在数据源更改时触发(您猜对了!),这样您就可以使用GetFocusedObject()获取对象并显示其他网格的相关项…

在类似情况下,我订阅

FocusedRowObjectChanged


事件(使用DevExpress 16.1)。

当我按照KB文章中的说明操作时,我可以在调试器中输入DoChangeFocusedRowInternal事件(请参见上文),并逐步完成代码。但是我的网格从来没有被可视化渲染过。我遗漏了什么?当我试图将MyGrid(按KB继承)从工具箱放到表单上时,VS2010崩溃了。我希望DevExpress能够调用这个小优化(FocusedRowHandle==newRowHandle)返回;)默认情况下,除非使用开发人员可以设置的某些设计时属性将其关闭,否则将按照原始问题更改数据源。我不知道您正在使用的代码,因此无法对其进行评论。无论如何,我已经用所有必修课更新了我的答案。我希望,它会对您有所帮助。更改确实允许将派生控件拖放到窗体上。但是RowEqual方法中的代码不起作用(逻辑上也不能起作用),因为focusedRowHandle为0,newRowHandle也为0,所以GetDataRow()方法必须返回同一行。请记住,原始数据源已替换为新数据源,此时在代码中只能引用当前数据源中的行。除了(int)行句柄之外,还需要类似于RowGUID的东西。@Tim,我的代码只是关于如何实现此功能的示例。您更了解任务,因此如果此代码有效,那么根据您的需求修改它应该不会有问题……是的,但是DataSourceChanged会导致意大利面条。关键是要能够在一个地方以一种方式做到这一点。我想问一个简单的问题:“我看的是另一行吗?”DevExpress问了一个更复杂的问题:“这一行在数组中占据不同的位置吗?”因为底层数据源可能会发生变化,使用数组位置作为相同/不同的指示器不如使用行对象固有的东西,像行GUID。我们升级的另一个原因。这将有助于我证明这一点。谢谢
namespace MyXtraGrid {

        public class MyGridControl : GridControl {
            protected override BaseView CreateDefaultView() {
                return CreateView("MyGridView");
            }
            protected override void RegisterAvailableViewsCore(InfoCollection collection) {
                base.RegisterAvailableViewsCore(collection);
                collection.Add(new MyGridViewInfoRegistrator());
            }
        }

        public class MyGridViewInfoRegistrator : GridInfoRegistrator {
            public override string ViewName { get { return "MyGridView"; } }
            public override BaseView CreateView(GridControl grid) {
                return new MyGridView(grid as GridControl);
            }
        }
        public class MyGridView : GridView {
            public MyGridView(GridControl ownerGrid) : base(ownerGrid) { }
            public MyGridView() { }


            protected virtual bool RowEqual(int focusedRowHandle, int newRowHandle) {
                if(IsDesignMode)
                    return focusedRowHandle == newRowHandle;
                DataRow row1 = GetDataRow(focusedRowHandle);
                DataRow row2 = GetDataRow(newRowHandle);
                return row1 == row2;
            }

            protected override void DoChangeFocusedRowInternal(int newRowHandle, bool updateCurrentRow) {
                if(this.lockFocusedRowChange != 0) return;
                if(!IsValidRowHandle(newRowHandle))
                    newRowHandle = DevExpress.Data.DataController.InvalidRow;
                if(RowEqual(FocusedRowHandle, newRowHandle))
                    return;
                int currentRowHandle = FocusedRowHandle;
                BeginLockFocusedRowChange();
                try {
                    DoChangeFocusedRow(FocusedRowHandle, newRowHandle, updateCurrentRow);
                }
                finally {
                    EndLockFocusedRowChange();
                }
                RaiseFocusedRowChanged(currentRowHandle, newRowHandle);
            }
        }
    }