C#编辑DataRow中的单个值成功但无限运行

C# Editing a single value in DataRow succeeds but runs infinitely

Scenario: 这是在一个WinForm项目中查看带有一些额外相关数据的图像,用户可以通过一个列表框在图像之间切换,所有图像的数据都存储在一个DataTable,每次用户改变listBox的选中索引,SelectedIndexChanged()会找到选中img名称的图片的DataRow,最初所有图片的DataTable都不包含分辨率数据,所以我是试图读取图像分辨率并保存到选定的 DataRow(例如,实际上将“Resolution”值从“”更改为 600),我将 DataRow currentGSImgInfo 设置为一个字段变量,每次 selectedIndex 更改时,它都与新值,代码如下(都在SelectedIndexChanged()里面):

imgDir = baseDir + "\TestDir\" + selectedGSImgName + ".jpg"; //TODO Dir
gsBitmapOri = new Bitmap(imgDir);//Get original bitmap
Bitmap initGSViewBitmap = new Bitmap(gsBitmapOri, new Size((int)(gsBitmapOri.Width * 0.066), (int)(gsBitmapOri.Height * 0.066))); 
gsBitmapCur = initGSViewBitmap;
gsZoomFactor = 0.066;
gsManualAdjust = false; //Initialize to enable auto adjust.
currentGSImgLocation = new Point(0, 0);
this.txtBox_startDepth.Text = "";//After change, re-initialize textual data
this.txtBox_endDepth.Text = "";
currentGSImgInfo = GSImgInfoOri.Select("coreNum = '" + this.listBox_selectGSImg.Text + "'")[0];
float imgDpi = gsBitmapOri.HorizontalResolution;
currentGSImgInfo.BeginEdit();
currentGSImgInfo[6] = imgDpi; //Where "resolution" is
currentGSImgInfo.EndEdit();
currentGSImgInfo.AcceptChanges();
GC.Collect(); //Recycle previous img from RAM
pictureBox_GS.Invalidate();

问题是,当代码运行到currentGSImgInfo.EndEdit()时,如果我不设置断点,它就会一直执行,导致程序没有响应,但如果我设置断点selectedIndexChanged() 函数的开头,它命中该断点并执行直到 EndEdit() 并再次命中断点。 “分辨率”的值已正确更改。 更糟糕的是,当程序第一次运行时,selectedIndexChanged()第一次调用,完全没有问题,它成功执行了currentGSImgInfo.EndEdit();并执行了接下来的任何预期,但是当我选择下img,问题就出现了。我没有绑定currentGSImgInfo到任何组件,它只是用来存储当前图像的数据,请问如何解决这个问题?

您可以尝试以下操作:

private bool BusySelectedIndexChanged; // used later to avoid re-entrancy
private void listBox_SelectedIndexChanged(object sender, EventArgs e)
{
    // REENTRANCY
    if (BusySelectedIndexChanged) // already running
        return;
    BusySelectedIndexChanged = true; // prevent re-entrancy
    try
    {
        imgDir = baseDir + "\TestDir\" + selectedGSImgName + ".jpg"; //TODO Dir
        gsBitmapOri = new Bitmap(imgDir);//Get original bitmap
        Bitmap initGSViewBitmap = new Bitmap(gsBitmapOri, new Size((int)(gsBitmapOri.Width * 0.066), (int)(gsBitmapOri.Height * 0.066))); 
        gsBitmapCur = initGSViewBitmap;
        gsZoomFactor = 0.066;
        gsManualAdjust = false; //Initialize to enable auto adjust.
        currentGSImgLocation = new Point(0, 0);
        this.txtBox_startDepth.Text = "";//After change, re-initialize textual data
        this.txtBox_endDepth.Text = "";
        float imgDpi = gsBitmapOri.HorizontalResolution;
        
        currentGSImgInfo = GSImgInfoOri.Select("coreNum = '" + this.listBox_selectGSImg.Text + "'")[0];

        // REALLY CHANGED ?
        // Only if value is changing
        if (imgDpi != currentGSImgInfo[6])
        {
            currentGSImgInfo.BeginEdit();
            currentGSImgInfo[6] = imgDpi; //Where "resolution" is
            currentGSImgInfo.EndEdit();
            currentGSImgInfo.AcceptChanges();
        }
        
        GC.Collect(); //Recycle previous img from RAM
        pictureBox_GS.Invalidate();
    }
    finally
    {
        BusySelectedIndexChanged = false;
    }
}

它通过设置和清除字段 BusySelectedIndexChanged 来避免 re-entrancy:if/try/finally 块确保内部代码永远不会 运行 在无限循环中。

根据您的需要,一些代码可能会移到 if/try/finally 块之前(在 "// REENTRANCY" 之前)。 无限循环的真正原因可能在别处。例如,由 EndEdit/AcceptChanges 触发的某些事件又会更改列表框内的索引:如果列表框被清除并且 re-populated.

通常会发生这种情况

奖励:不要忘记处置临时 IDisposable 对象(如 initGSViewBitmap)。