【问题标题】:What Exactly Happens in C# When PictureBox.Visible Is Set to True?当 PictureBox.Visible 设置为 True 时,C# 中究竟发生了什么?
【发布时间】:2017-08-01 12:01:39
【问题描述】:

我正在创建一个带有图片框的 WinForms 应用程序,这些图片框默认情况下被禁用且不可见。当我单击表单中的单选按钮时,我希望出现图片框,然后立即在它们上绘制一些东西:

// the radio button CheckedChanged event handler:
table1PictureBox.Enabled = true;
table1PictureBox.Visible = true;
DrawCorrectAnswers();  // draw something over the picture box

问题是绘图在图片可见之前就完成了,所以绘图最终被图片覆盖了。

在解决我阅读here 的问题时,在 Visibility 设置为 true 后,实际的图像加载在表单的消息队列中排队。答案甚至建议一个可能的解决方案是设置一个计时器,然后异步等待它的滴答声,然后进行绘图,以便图片有时间加载。我不喜欢设置计时器的解决方案,而是想等待图片本身被加载。

有没有办法做到这一点?在这种情况下,将 Visible 设置为 true 究竟是如何工作的?


我还尝试提出一个替代解决方案,如下所示:

// the radio button CheckedChanged event handler:
table1PictureBox.Enabled = true;
table1PictureBox.Visible = true;
this.BeginInvoke(new Action(() => { DrawCorrectAnswers(); }));  // 'this' is the form

我的想法是,这将在加载消息之后将要绘制的消息排入队列,因此即使操作也将按所需的顺序执行。然而,这也不起作用。

在这种情况下,如果我在表单的线程中,是否会出现 BeginInvoke 的特殊行为?我什至尝试了正常的调用,令我惊讶的是,它并没有导致死锁。这是为什么呢?


[编辑] 这是一个说明问题的最小示例:

public Form1()
    {
        InitializeComponent();

        pictureBox1.Visible = false;
        pictureBox1.Enabled = false;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        pictureBox1.Enabled = true;
        pictureBox1.Visible = true;

        Graphics graphics = pictureBox1.CreateGraphics();
        graphics.DrawLine(Pens.Black, 0, 0, 50, 50);
    }

【问题讨论】:

标签: c# winforms picturebox synchronizationcontext


【解决方案1】:

这里的问题是你在画框上绘图,而不是在图像上,每当控件被重绘时,你在它上面绘制的所有东西都将被删除,你需要重绘它。

更好的解决方案是手动加载图片,在图片上绘制文字,然后设置到图片框:

private void button1_Click(object sender, EventArgs e)
{

    Bitmap bmp = Bitmap.FromFile(pathToTheFile);

    using(var graphics = Graphics.FromImage(bmp))
        graphics.DrawLine(Pens.Black, 0, 0, 50, 50);

    var oldImg = pictureBox1.Image;
    pictureBox1.Image = bmp;

    if(oldImg != null)
      oldImg.Dispose();

    pictureBox1.Enabled = true;
    pictureBox1.Visible = true;

}

注意一些事情:始终处理您创建的任何 Graphics 对象,最好用 using 块包围它。另外,在不需要时丢弃任何未使用的图像,这就是我检索旧图像并在存在时将其丢弃的原因。

最后,如果您不想将图像作为物理文件包含在内,您可以将其作为资源嵌入,有很多示例说明如何做到这一点。

编辑:

当您将 Visible 设置为 true 时,幕后发生的事情是 PictureBox 区域在表单上无效,然后在下一个 Draw 循环中,表单将测试哪些可见控件与该矩形(或任何其他无效区域)相交并且然后将它们绘制出来。

另外,关于调用,为什么会导致死锁?您没有使用任何锁,当您调用 Invoke 时,它​​将检查线程,如果线程是 UI 线程,则它将执行该函数,否则它将调用发布到 UI 线程并且调用线程将被阻塞,直到UI 已处理函数调用。

【讨论】:

  • 谢谢,这比我的方法更有意义!
  • @honzukka 如果回答正确,请采纳。
  • 我仍然希望得到其他问题的答案。我了解您的方法按我需要的方式工作,但我仍然不明白我的尝试到底出了什么问题。有些概念我还不清楚。那我是不是把问题用错了? (如您所见,这是我在这里的第一篇文章...:D)
猜你喜欢
  • 2015-12-25
  • 2013-06-13
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多