我正在使用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);
Run Code Online (Sandbox Code Playgroud)
在我的代码中调用以适当地绘制世界:
view.DrawWorldBox(worldBox, canvas, gameEngine.GameObjectManager.Controllers,
selectedGameObjects, LevelEditorUtils.PREVIEWS);
Run Code Online (Sandbox Code Playgroud)
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();
}
Run Code Online (Sandbox Code Playgroud)
我在这里做错了什么?
Aar*_*ght 19
要理解这一点,您必须对操作系统级别的工作方式有所了解.
绘制Windows控件以响应WM_PAINT消息.当他们收到此消息时,他们会绘制自己无效的部分.可以使特定控件无效,并且可以使控件的特定区域无效,这样做是为了最小化重新绘制的量.
最终,Windows将看到某些控件需要重新绘制并向其发出WM_PAINT消息.但它只在处理完所有其他消息后执行此操作,这意味着Invalidate不会强制立即重绘. Refresh技术上应该,但并不总是可靠的.(更新:这是因为Refresh是virtual和有在重写此方法的使用不正确的实施野生某些控件.)
有一个方法,不通过发出强制立即油漆WM_PAINT的消息,那就是Control.Update.因此,如果您想强制立即重绘,请使用:
control.Invalidate();
control.Update();
Run Code Online (Sandbox Code Playgroud)
即使UI仍在处理消息,这也将始终重绘控件,无论发生什么.从字面上看,我相信它使用的是SendMessageAPI,而不是PostMessage将绘制的力同步完成,而不是在长消息队列的末尾抛出它.