如何在C#中在后台更新数据时如何防止virtualmode datagridview调用所需的cellvalue [英] How to keep virtualmode datagridview from calling cellvalueneeded while updating data in the background in C#

查看:70
本文介绍了如何在C#中在后台更新数据时如何防止virtualmode datagridview调用所需的cellvalue的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个VirtualMode = true的datagridview,我还实现了拖放操作,以使用户能够对datagridview中的行重新排序。我的问题是即使我正在使用SuspendLayout / ResumeLayout,在处理过程中datagridview仍在调用CellValueNeeded导致程序崩溃。

I have a datagridview with VirtualMode = true that I have also implemented drag/drop to enable the user to reorder rows within the datagridview. My issue is even though I am using SuspendLayout/ResumeLayout, the datagridview is still calling CellValueNeeded in the middle of processing causing my program to crash.

在DragDrop事件中,我包含以下代码,其中'dragRow'是源行,'row'是拖放事件的目的地。

Within the DragDrop event, I have the following code where 'dragRow' is the source row and 'row' is the destination of the drag/drop event.

gridview.SuspendLayout();
try
{
    // copy dragged row
    DataGridViewRow rowCopy = gridview.Rows[dragRow];
    DataValue dataCopy = dataList[dragRow];

    // remove dragged row
    dataList.RemoveAt(dragRow);
    gridview.Rows.RemoveAt(dragRow);

    // insert row
    dataList.Insert(row, dataCopy);
    gridview.Rows.Insert(row, rowCopy);

    // move selection to moved row
    gridview.CurrentCell = gridview[gridview.CurrentCell.ColumnIndex, row];
}
finally { gridview.ResumeLayout(true); }

在开始拖放之前,我的程序检测到用户选择了最后一行。我将最后一行设计为始终为空,原因是我不打算进入这里。通常,如果用户选择最后一行,则仅在启用DragDropEffects.Copy选项的情况下启动拖放。如果我检测到倒数第二行也为空,那么我将拖动的行切换到倒数第二行,以使用户能够移动空白行(因为最后一行不可移动)。问题是在DragDrop事件期间,在该行从数据列表中删除该行到将其插入新位置之间,datagridview调用其CellValueNeeded事件,导致我的程序在尝试从中读取内容时发生超出范围的异常崩溃我的数据列表不存在。

Before the drag/drop is initiated, my program detects that the user selected the last row. I have designed the last row to always be empty for reasons I am not going to get into here. Usually if the user selects the last row, then it initiates the drag/drop with only the DragDropEffects.Copy option enabled. If I detect the second to last row is also empty, then I switch the row being dragged to the second to last row to enable the user to move the blank row (as the last row is not movable). The issue is during the DragDrop event between where the row is removed from my data list to where it is inserted in the new location the datagridview calls its CellValueNeeded event causing my program to crash on an out of range exception as it tries to read something from my data list that is not there.

我还看到了与显示工具提示有关的问题。如果用户将鼠标悬停在他们刚刚拖动的行/单元格内,则显示的工具提示是针对错误的行,就像针对错误的单元格引发了CellToolTipTextNeeded事件,并且在ResumeLayout之后未更新。

I have also seen this issue in relation to tool tips being displayed. If the user hovers the mouse within the row/cell they just dragged, then the tool tip displayed is for the wrong row as if the CellToolTipTextNeeded event was raised for the wrong cell and not updated after the ResumeLayout.

是否缺少我应该做的事以便让datagridview知道我正在虚拟模式下更新其数据源?

Is there something I'm missing that I should be doing to let the datagridview know I'm updating its data source while in virtualmode?

作为参考,以下CellValueNeeded处理程序是由于gridview试图从行 dataList.RemoveAt(dragRow);之后的dataList中不再存在的行中读取而引发IndexOutOfRangeException的示例;

For reference, the following CellValueNeeded handler is example of where IndexOutOfRangeException is being thrown due to gridview trying to read from row that no longer exists in dataList after line dataList.RemoveAt(dragRow); in above code.

private void gridview_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
    switch (e.ColumnIndex)
    {
        case 2: // Name
            e.Value = dataList[e.RowIndex].Name;
            break;
        case 3: // Value
            e.Value = dataList[e.RowIndex].Value;
            break;
    }
}


推荐答案

您问两个问题:

第一个
问:如何在更新后台数据时保持虚拟模式datagridview不调用需要的单元格值C#?

First: Q: "How to keep virtualmode datagridview from calling cellvalueneeded while updating data in the background in C#?"

A:我的建模表明,这条线是明显导致CellValueNeeded被调用的原因:

A: My modeling shows that this line is what explicitly causes CellValueNeeded to be called:

gridview.CurrentCell = gridview[gridview.CurrentCell.ColumnIndex, row];

将其包装在SuspendLayout中不会改变事实。如果要避免在 this 方法中调用CellValueNeeded,请删除此行,然后在其他位置调用。

Wrapping it in SuspendLayout does not change the fact. If you want to avoid CellValueNeeded being called in this method, then remove this line and call it elsewhere.

第二 >
问:是否缺少我应该做的事,让datagridview知道我正在虚拟模式下更新其数据源?

Second Q: "Is there something I'm missing that I should be doing to let the datagridview know I'm updating its data source while in virtualmode?"

A :(简短回答)

根据我的建模,如果满足以下条件,您的代码将正常运行而不会引发异常:

According to my modeling, your code will work without throwing exceptions if:


  • 考虑到如果控件由于任何原因由于任何原因重新绘制了 ,则将调用CellValueNeeded 您的应用程序或其他窗口活动或鼠标状态更改(包括控件上的任何鼠标移动)。

  • It takes into account that CellValueNeeded will be called if the control redraws for any reason at any time whether caused by your application or some other window activity or mouse state change (which included any mouse motion whatsoever over the control).

它完全保持这三个值同步次,如果删除或插入行,则立即更新

It maintains these three values in sync at all times, updating immediately if a row is removed or inserted:


  • DGV的行数

  • 数据源的计数

  • Th如果AllowUserToAddRows属性为true,则RowCount需要1的偏移量。

您解决了代码中的一个错误:您正在尝试使用操纵行的删除和插入int 索引值。无论如何,这种方法充满危险,但是在VirtualMode中尤其是 ,因为这些索引值与包含DataValue对象的源列表之间没有绑定。在按照您显示的方式进行编码的拖放操作中,在您插入或删除列表项时,这些索引值变得不可靠(即可能无法工作)

You address a bug in your code: That you are trying to manipulate the removal and insertions of rows using int index values. This approach is fraught with danger anyway, but particularly in VirtualMode because there is no binding between those index values and the source list containing the DataValue objects. In a drag drop operation coded in the manner you show, these index values become unreliable (i.e might-or-might-not-work) the moment you insert or remove a list item.

请尝试用它替换您帖子中的第一个代码块,让我知道它是否可以解决您的问题。 / p>

Please try substituting this for the first code block in your post and let me know if it fixes your problem.

try
{
    // We need to bank the actual objects here.
    DataValue
        draggedItem = dataList[dragRowIndex],
        dropTarget = dataList[dropRowIndex];

    // From here on out, anything index-based is doomed to 
    // spradically fail because we're changing the list by 
    // removing one or more items from it. There is no
    // binding between the two (you gave that up when you
    // set VirtualMode = true)

    dataList.RemoveAt(dragRowIndex); // Remove the dragged item(s)
    SynchronizeCounts();

    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    // CRITICAL:
    // So at what index is the drop target now?
    int correctDropRowIndex = dataList.IndexOf(dropTarget);
    // In many cases it's not the same as dropRowIndex!!
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    dataList.Insert(correctDropRowIndex, draggedItem);
    SynchronizeCounts();

    // move selection to moved row

    int safeColumnIndex = gridview.CurrentCell == null ? 0 : gridview.CurrentCell.ColumnIndex;
    int newIndexOfDroppedItem = dataList.IndexOf(draggedItem);

#if false
    // Setting CurrentCell is guaranteed to make calls
    // to CellValueChanged. You will have to do it elsewhere
    // if you don't want that to happen in this here code block.
    gridview.CurrentCell =
        gridview
        [
            columnIndex: safeColumnIndex,
            rowIndex: newIndexOfDroppedItem
        ];
#endif
}
catch (Exception e)
{
    Debug.Assert(false, e.Message);
}

...其中...

private void SynchronizeCounts()
{
    gridview.RowCount = dataList.Count;
    if (gridview.AllowUserToAddRows)
    {
        gridview.RowCount++;
    }
}

我们的GitHub有一个DataGridView VirtualMode示例,其中有很多诊断能力。如果您想对DGV进行更多代码分析,欢迎访问克隆或下载我们的Visual Studio解决方案。

Our GitHub has a DataGridView VirtualMode example with a lot of diagnostic capability. If you'd like to do more code analysis of your DGV you're welcome to Clone or Download our Visual Studio solution.

这篇关于如何在C#中在后台更新数据时如何防止virtualmode datagridview调用所需的cellvalue的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆