Home > Software engineering >  C# Editing a single value in DataRow succeeds but runs infinitely
C# Editing a single value in DataRow succeeds but runs infinitely

Time:05-11

Scenario: This is in a WinForm project to view images with some extra related data , the user can switch between images via a listBox, data of all the images are stored in a DataTable, and each time the user changes the selected index of the listBox, SelectedIndexChanged() will find the DataRow of the image with the selected img name, and initially the DataTable of all images does not contain resolution data, so I am trying to read the image resolution and save to the selected DataRow(actually change "Resolution" value from "" to 600 for example), I made the DataRow currentGSImgInfo a field variable and every time selectedIndex changes, it is assgined with new values, code below(This is all inside 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();

The problem is that when the code runs to currentGSImgInfo.EndEdit(), if I don't put a break point it just keeps excecuting, causing the program to be not responding, but if I put a break point at the beginning of selectedIndexChanged() function, it hits that break point and excutes until EndEdit() and hits the break point again. The value of "resolution" is correctly changed. To make things worse, when the program runs for the first time, selectedIndexChanged() called for the first time, there's no problem at all, it successfully excecutes currentGSImgInfo.EndEdit(); and do whatever that's expected next, but when I selected the next img, the problem occurs. I did not bind currentGSImgInfo to any component, it is only used to store the data of the current image, how could I resolve this problem?

CodePudding user response:

You can try something like the following:

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

It avoids re-entrancy by setting and clearing the field BusySelectedIndexChanged: the if/try/finally block ensures that the inner code is never run in an infinite loop.

Based on your needs, some code might be moved before the if/try/finally block (before "// REENTRANCY"). It is possible that the real cause of the infinite loop is elsewhere. For example some event fired by EndEdit/AcceptChanges that in turn changes the index inside the listbox: that usually happens if the listbox is cleared and re-populated.

Bonus: don't forget to Dispose temporary IDisposable objects (like initGSViewBitmap).

  • Related