【发布时间】:2019-05-03 08:45:21
【问题描述】:
在我的 Winforms 应用程序中,我尝试重新创建蒙特卡洛方法来近似 PI。表单本身由一个框组成,用户在其中提供点的数量和一个面板,我想在其上进行绘制。不过,对于这个例子,我们假设金额是恒定的。
private int Amount = 10000;
private int InCircle = 0, Points = 0;
private Pen myPen = new Pen(Color.White);
private void DrawingPanel_Paint(object sender, PaintEventArgs e)
{
int w = DrawingPanel.Width, h = DrawingPanel.Height;
e.Graphics.TranslateTransform(w / 2, h / 2);
//drawing the square and circle in which I will display the points
var rect = new Rectangle(-w / 2, -h / 2, w - 1, h - 5);
e.Graphics.DrawRectangle(myPen, rect);
e.Graphics.DrawEllipse(myPen, rect);
double PIE;
int X, Y;
var random = new Random();
for (int i = 0; i < Amount; i++)
{
X = random.Next(-(w / 2), (w / 2) + 1);
Y = random.Next(-(h / 2), (h / 2) + 1);
Points++;
if ((X * X) + (Y * Y) < (w / 2 * h / 2))
{
InCircle++;
e.Graphics.FillRectangle(Brushes.LimeGreen, X, Y, 1, 1);
}
else
{
e.Graphics.FillRectangle(Brushes.Cyan, X, Y, 1, 1);
}
//just so that the points appear with a tiny delay
Thread.Sleep(1);
}
PIE = 4 * ((double)InCircle/(double)Points);
}
这很有效。可视化很棒。 但是,现在我想异步重新创建它,这样当它在后台绘制时,应用程序仍然负责,用户可以做其他事情,甚至只是移动窗口。 最初我创建了第二种绘图方法,我从事件处理程序中调用它:
private double Calculate(PaintEventArgs e)
{
int w = DrawingPanel.Width, h = DrawingPanel.Height;
double PIE;
int X, Y;
var random = new Random();
for (int i = 0; i < Amount; i++)
{
X = random.Next(-(w / 2), (w / 2) + 1);
Y = random.Next(-(h / 2), (h / 2) + 1);
Points++;
if ((X * X) + (Y * Y) < (w / 2 * h / 2))
{
InCircle++;
e.Graphics.FillRectangle(Brushes.LimeGreen, X, Y, 1, 1);
}
else
{
e.Graphics.FillRectangle(Brushes.Cyan, X, Y, 1, 1);
}
Thread.Sleep(1);
}
PIE = 4 * ((double)InCircle/(double)Points);
return PIE;
}
private void DrawingPanel_Paint(object sender, PaintEventArgs e)
{
int w = DrawingPanel.Width, h = DrawingPanel.Height;
e.Graphics.TranslateTransform(w / 2, h / 2);
var rect = new Rectangle(-w / 2, -h / 2, w - 1, h - 5);
e.Graphics.DrawRectangle(myPen, rect);
e.Graphics.DrawEllipse(myPen, rect);
var result = Calculate(e);
}
这也很好用。直到我使事件处理程序异步。
private async void DrawingPanel_Paint(object sender, PaintEventArgs e) {...}
现在,当我尝试通过 Task.Run 运行 Calculate 方法时,或者当我将其返回类型更改为 Task 并启动它时,我收到以下行中的错误:“Parameter is not valid”:
e.Graphics.FillRectangle(Brushes.LimeGreen, X, Y, 1, 1);
现在的问题是,是否可以异步在面板上绘图,从而不锁定应用程序的其他部分?如果没有,有没有办法使用任何其他方式(不一定是面板)重新创建这个算法?干杯。
【问题讨论】:
-
无法从工作线程直接绘制到屏幕上。
-
异步 void 事件处理程序存在 很多 问题。这肯定是其中之一, e.Graphics 对象仅在第一次调用中有效。之后它被处置并在继续时变得无效。 winforms 管道只是对异步代码一无所知,该功能在 winforms 冻结很久之后就被固定了。没有令人信服的理由来改进它,如果它可以工作,那么它只会像廉价汽车旅馆一样闪烁。您必须停止尝试使其异步,它无法工作。
-
您可以在
for循环的末尾添加Application.DoEvents()以使应用程序响应。 -
@YeldarKurmangaliyev 这实际上满足了我的要求。非常感谢!
-
但我认为任何可能的好处都将丢失..
标签: c# winforms asynchronous system.drawing