加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

C#:Windows窗体:可能会导致Invalidate()不重绘?

发布时间:2020-12-15 06:50:11 所属栏目:百科 来源:网络整理
导读:我正在使用 Windows窗体.很长一段时间,pictureBox.Invalidate();努力使屏幕重绘.但是,现在不行,我不知道为什么. this.worldBox = new System.Windows.Forms.PictureBox();this.worldBox.BackColor = System.Drawing.SystemColors.Control;this.worldBox.Bord
我正在使用 Windows窗体.很长一段时间,pictureBox.Invalidate();努力使屏幕重绘.但是,现在不行,我不知道为什么.
this.worldBox = new System.Windows.Forms.PictureBox();
this.worldBox.BackColor = System.Drawing.SystemColors.Control;
this.worldBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.worldBox.Location = new System.Drawing.Point(170,82);
this.worldBox.Name = "worldBox";
this.worldBox.Size = new System.Drawing.Size(261,250);
this.worldBox.TabIndex = 0;
this.worldBox.TabStop = false;
this.worldBox.MouseMove += new 
    System.Windows.Forms.MouseEventHandler(this.worldBox_MouseMove);
this.worldBox.MouseDown += new 
    System.Windows.Forms.MouseEventHandler(this.worldBox_MouseDown);
this.worldBox.MouseUp += new 
    System.Windows.Forms.MouseEventHandler(this.worldBox_MouseUp);

在我的代码中被称为适当地画出世界:

view.DrawWorldBox(worldBox,canvas,gameEngine.GameObjectManager.Controllers,selectedGameObjects,LevelEditorUtils.PREVIEWS);

View.DrawWorldBox:

public void DrawWorldBox(PictureBox worldBox,Panel canvas,ICollection<IGameObjectController> controllers,ICollection<IGameObjectController> selectedGameObjects,IDictionary<string,Image> previews)
{
    int left = Math.Abs(worldBox.Location.X);
    int top = Math.Abs(worldBox.Location.Y);
    Rectangle screenRect = new Rectangle(left,top,canvas.Width,canvas.Height);

    IDictionary<float,ICollection<IGameObjectController>> layers = 
        LevelEditorUtils.LayersOfControllers(controllers);
    IOrderedEnumerable<KeyValuePair<float,ICollection<IGameObjectController>>> sortedLayers 
            = from item in layers
              orderby item.Key descending
              select item;

    using (Graphics g = Graphics.FromImage(worldBox.Image))
    {
        foreach (KeyValuePair<float,ICollection<IGameObjectController>> 
        kv in sortedLayers)
        {
            foreach (IGameObjectController controller in kv.Value)
            {
                // ...

                float scale = controller.View.Scale;
                float width = controller.View.Width;
                float height = controller.View.Height;
                Rectangle controllerRect = new 
                    Rectangle((int)controller.Model.Position.X,(int)controller.Model.Position.Y,(int)(width * scale),(int)(height * scale));

                // cull objects that aren't intersecting with the canvas
                if (controllerRect.IntersectsWith(screenRect))
                {
                    Image img = previews[controller.Model.HumanReadableName];
                    g.DrawImage(img,controllerRect);
                }

                if (selectedGameObjects.Contains(controller))
                {
                    selectionRectangles.Add(controllerRect);
                }
            }
        }
        foreach (Rectangle rect in selectionRectangles)
        {
            g.DrawRectangle(drawingPen,rect);
        }
        selectionRectangles.Clear();
    }
    worldBox.Invalidate();
}

在这里我可以做错什么

解决方法

要理解这一点,您必须对操作系统级别的工作方式有所了解.

Windows控件是为响应WM_PAINT消息而绘制的.当他们收到这个消息时,他们绘制自己的哪一部分已经被无效.特定控制可以被无效,并且控制的特定区域可以被无效,这一切都是为了尽量减少重新绘制的量.

最终,Windows会看到一些控件需要重画,并向他们发出WM_PAINT消息.但是,只有在处理完所有其他消息后才能执行此操作,这意味着Invalidate不会强制立即重绘.在技??术上刷新应该,但并不总是可靠的. (更新:这是因为刷新是虚拟的,并且有一些控件在野外覆盖此方法与不正确的实现.)

有一种方法通过发出WM_PAINT消息强制立即绘制,即Control.Update.所以如果要强制立即重画,您可以使用:

control.Invalidate();
control.Update();

即使UI仍在处理消息,这将始终重绘控件,无论发生了什么.从字面上来说,我相信它使用SendMessage API而不是PostMessage,它强制绘画同步完成,而不是在长消息队列的末尾将它们折腾.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读