我一直在使用C#/ Visual Studio中的这个简单的乘法表程序,这给我带来了麻烦,因为循环(特别是do-while)对我来说非常困难。我应该使用嵌套的for循环和嵌套的do-while循环,虽然我没有收到任何错误,但是当我调试或运行程序并单击 while循环按钮时,它会冻结并需要要停下来; for-loop 按钮在点击时仅显示“0”,但执行循环按钮似乎正常工作。
我相信这些是有问题的部分 - for loop:
for i in range(100):
while-loop:
for (r = 1; r < 10; r++)
{
for (c = 1; c < 10; c++)
{
intResult = r * c;
if (intResult < 10)
strSpace = " "; //two spaces
else
strSpace = " "; //one space
txtTable.AppendText(strSpace); // insert space
txtTable.AppendText(intResult.ToString()); //insert result
txtTable.AppendText("\r\n"); //Move down one line
}
}
}
完整的参考代码:
private void btnWhileLoop_Click(object sender, EventArgs e)
{
int r = 0; //row
int c = 0; //column
int intResult;
string strSpace;
txtTable.Clear(); //clear the text box
txtTable.Refresh(); //refresh the form before exiting the method
Thread.Sleep(1000); //wait one second to see the clear text box
//Outer loop goes down the rows
r = 1; //initialize r
do
{
//Inner loop goes across the columns
c = 1; //initialize c
do
{
intResult = r * c;
} while (r < 10);
} while (c < 10);
strSpace = " ";
txtTable.AppendText(strSpace); // insert space
txtTable.AppendText(intResult.ToString()); //insert result
c++; //increment c
{
txtTable.AppendText("\r\n"); //Move down one line
r++; //increment r
}
}
谢谢。
答案 0 :(得分:2)
你有两个不同的问题,但两者都是由同一个根本错误引起的:你在处理事情时不会让UI线程更新。
顺便说一句:您的代码非常混乱。您的活动处理程序的名称似乎与他们实际所做的不相符。例如,do
/ while
示例位于名为btnWhileLoop_Click()
的方法中,而嵌套for
循环示例位于名为btnDoWhileLoop_Click()
的方法中。然后你有一个名为btnForLoop_Click()
的方法,根本没有任何循环。出于本答案的目的,我将至少忽略方法名称,因为它们与特定实现相关,并且仅用于识别每种方法。
总之...
在do
/ while
示例中,主要问题是您没有更改控制循环的变量。因为它永远不会改变,所以允许循环终止的表达式永远不会计算为false
,因此循环只会永远运行。
在同样的方法中,你有一堆代码,看起来你最初可能已经正确地编写了它,然后你的小兄弟出现并将你的程序从桌面上敲下来,这样当你选择备份时,你只需按随机顺序将它们设置回方法即可。即似乎所有正确的位都存在,但它们不是任何连贯的顺序。
这是一个应该更好的方法版本:
private void btnWhileLoop_Click(object sender, EventArgs e)
{
int r = 0; //row
int c = 0; //column
int intResult;
string strSpace;
txtTable.Clear(); //clear the text box
txtTable.Refresh(); //refresh the form before exiting the method
Thread.Sleep(1000); //wait one second to see the clear text box
//Outer loop goes down the rows
r = 1; //initialize r
do
{
//Inner loop goes across the columns
c = 1; //initialize c
do
{
intResult = r * c;
c++; //increment c
txtTable.AppendText(" "); // insert space
txtTable.AppendText(intResult.ToString()); //insert result
} while (c < 10);
txtTable.AppendText("\r\n"); //Move down one line
r++; //increment r
} while (r < 10);
}
上面的问题仍然是在整个过程完成之前屏幕上没有任何变化。但至少现在可以完成整个事情。 :)我将使用嵌套的for
循环示例来说明如何解决第二个问题,即在整个过程完成之前屏幕上没有显示任何内容。
有多种方法可以解决这个问题,但恕我直言最常用和自然的方法是在后台任务中运行你的处理,并让UI线程同时工作。这可能看起来像这样:
private async void btnDoWhileLoop_Click(object sender, EventArgs e)
{
int r = 0; //row
int c = 0; //column
int intResult;
string strSpace;
txtTable.Clear(); //clear the text box
await Task.Delay(1000); //wait one second to see the clear text box
txtTable.AppendText("\r\n");
// set up a helper to make it easy to update the UI from the background
// task Non-standard event arg type of "string", because we don't need
// anything fancier
Progress<string> progress = new Progress<string>();
// This event is raised when progress.Report() is called (see below)
progress.ProgressChanged += (sender, e) =>
{
txtTable.AppendText(e);
};
// Wrap the loops in an anonymous method (i.e. the () => { ... } syntax)
// and pass that to Task.Run() so it can run as a background task
await Task.Run(() =>
{
//Outer loop goes down the rows
//initialize r
//do
//Inner loop goes across the columns
//initialize c
//do
for (r = 1; r < 10; r++)
{
for (c = 1; c < 10; c++)
{
intResult = r * c;
if (intResult < 10)
strSpace = " "; //two spaces
else
strSpace = " "; //one space
// While the task is running in a thread other than your original
// UI thread, using the "progress" object here allows the task to pass
// data back to the UI thread where it is allowed to call e.g.
// txtTable.AppendText() to update the UI.
progress.Report(strSpace); // insert space
progress.Report(intResult.ToString()); //insert result
}
// I think you wanted this line outside the inner loop
progress.Report("\r\n"); //Move down one line
}
});
// There's nothing else to do. But if you wanted to you could add code here
// to do something after the task is run. Using "await" allows the UI thread
// to keep running while the task is running, and then return control to
// this method here when it's done.
}
备注:强>
async
关键字用于标记使用await
关键字的方法。您可以在其他地方阅读有关如何使用这些内容的详简短版本是使用await
允许该方法实际返回到调用者临时,以便调用该方法的线程可以继续运行,而方法本身正在等待某些事情发生。当发生这种情况时,该方法将在await
语句或表达式之后继续执行。这是一种关键技术,允许UI线程继续工作,而其他任务在另一个线程中运行。Progress<T>
类。这个类隐藏了所需的所有血腥细节(参见例如Control.Invoke()
方法),并且可以很容易地以直接的方式将数据传递回UI线程。progress
对象)时,UI可以通过重绘自身并在任务仍在运行时在屏幕上显示新数据来响应您的更新。Thread.Sleep(100)
语句抛出到内部循环中,以便在实际进行时看到事情发生。只有100次迭代,完全有可能没有它,即使UI线程未被阻止,仍然不会更新,直到处理结束。do
/ while
示例),以便在循环实际运行时也可以更新UI。 / LI>