【问题标题】:DevExpress XtraGrid FocusedRowChanged event problem when changing datasource更改数据源时的 DevExpress XtraGrid FocusedRowChanged 事件问题
【发布时间】:2011-05-05 19:37:26
【问题描述】:

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

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

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

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

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

以下是它不起作用的原因:假设在某一天,用户必须联系的客户列表仅包含一行。所以网格中的第一行(也是唯一的)是焦点行。现在假设用户进入菜单并选择菜单项以显示当天的自助餐厅主菜。当用户单击 Entrees 列表中的第一项时,FocusedRowChanged 事件不会触发,因为网格保留了来自前一个数据源的焦点行索引的内存。焦点行 index 没有改变。因此用户的选择不会触发任何事情。

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

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

【问题讨论】:

    标签: devexpress xtragrid


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      在类似的情况下,我订阅了

      FocusedRowObjectChanged

      事件(使用 DevExpress 16.1)。

      【讨论】:

      • 我们升级的另一个原因。这将帮助我证明这一点。谢谢。
      【解决方案3】:

      我认为这个问题的最佳解决方案是创建一个新的 GridView 对象并覆盖它的 DoChangeFocusedRowInternal 方法。您将在下面找到此方法的默认实现。您需要做的就是根据您的需要更改标记的行。另外,看看How to create a GridView descendant class and register it for design-time use 文章,它包含一些有用的信息。

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

      更新

      我的代码:

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

      【讨论】:

      • 当我按照知识库文章中的说明进行操作时,我可以在调试器中输入 DoChangeFocusedRowInternal 事件(见上文)并单步执行代码。但是我的网格永远不会在视觉上呈现。我错过了什么?
      • 当我尝试将 MyGrid(按 KB 继承)从 ToolBox 拖放到表单上时,VS2010 崩溃。我希望 DevExpress 可以在默认情况下调用那个小优化 (FocusedRowHandle==newRowHandle) return;) 除非它使用开发人员可以在数据源将要更改时设置的一些设计时属性关闭,根据原始问题。跨度>
      • 我不知道你使用的代码,所以我不能评论它。无论如何,我已经用所有必需的课程更新了我的答案。希望对您有所帮助。
      • 更改确实允许将派生控件拖放到表单上。但是 RowEqual 方法中的代码不起作用(并且逻辑上不能起作用),因为focusedRowHandle 为0 而newRowHandle 也是0,因此GetDataRow() 方法必须返回相同的行。请记住,原始数据源已被新数据源替换,此时在代码中您只能引用来自 CURRENT 数据源的行。除了 (int) RowHandle 之外,还需要有类似 RowGUID 的东西。
      • @Tim,我的代码只是关于如何实现此功能的示例。您更了解任务,因此如果此代码有效,则根据您的要求对其进行修改应该没有问题...
      【解决方案4】:

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

      【讨论】:

      • 是的,但是 DataSourceChanged 会导致意大利面。关键是能够在一个地方以一种方式做到这一点。 > 我想问一个简单的问题:“我在看不同的行吗?” DevExpress 提出了这个更复杂的问题:“这一行在数组中占据不同的位置吗?”由于底层数据源可以更改,因此使用数组位置作为相同/差异的指标不如使用行对象的内部属性(如行 GUID)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-29
      相关资源
      最近更新 更多