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
)。
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
)。