为什么最小化和恢复窗口会对WPF中已经绘制的图形产生影响

本文关键字:绘制 图形 影响 恢复 最小化 窗口 WPF 为什么 | 更新日期: 2023-09-27 17:50:48

我有一个非常基本的测试应用程序,仅由WindowCustomControl组成。该窗口包含自定义控件,并具有以下附加属性:

TextOptions.TextFormattingMode="Display"
SnapsToDevicePixels="True" 
UseLayoutRounding="True"
RenderOptions.EdgeMode="Aliased"

自定义控件将以下5行添加到代码隐藏文件中:

protected override void OnRender(DrawingContext drawingContext)
{
    var pen = new Pen(Brushes.Black, 1);
    drawingContext.DrawLine(pen, new Point(0, 0), new Point(ActualWidth, ActualHeight)); 
}

一切都很好。从左上角到右下角对角线绘制一条1px的黑色线。完美的。诚然有点像素化,但正是我需要的。然而,当我最小化窗口并再次恢复它时,线条变得"模糊"。这发生在没有OnRender方法被再次调用后,窗口已经恢复。那么,为什么在最小化窗口后绘制的图形会发生根本性的变化(失去焦点似乎不是问题)?为什么一切都恢复正常后,窗口只是简单地调整大小,我怎么能照顾这种不想要的行为?每次WindowState更改时强制完全调整大小/无效似乎有点过分,不是吗?

更新1:

正如@Backlash建议的那样,我把自定义控件放在画布中

<Canvas Name="CanvasControl" SizeChanged="FrameworkElement_OnSizeChanged">
  <wpfTest:CustomControl x:Name="ChildControl" />
</Canvas>

并像这样处理SizeChanged事件

private void FrameworkElement_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
    ChildControl.Width = CanvasControl.ActualWidth;
    ChildControl.Height = CanvasControl.ActualHeight;
}

,因为画布中的元素不会自动布局。然而,结果并没有改变。

更新2:

我脑海中闪过的一个想法是倾听窗口状态的变化,并通过稍微改变窗口的WidthHeight属性来强制调整窗口及其所有控件的大小,从而完全重新绘制:

protected override void OnStateChanged(EventArgs e)
{
        if (WindowState != WindowState.Minimized)
        {               
            Width += 1;
        }
}

这在某些情况下是有效的(虽然不是当Window最大化时),但一般来说,这是一个明显的坏方法,原因有很多。我试图理解是什么原因导致(正确的)重绘当大小改变,它可能与CoreFlags.AreTransformsClean有关,但由于一切都是内部或私有的,我放弃了使用这些标志和任何相关的方法。

更新3:

考虑到WPF似乎无法在屏幕上直接绘制直线,我尝试先在内存中绘制位图,然后再将位图绘制到屏幕上。这是有效的。方法如下:

protected override void OnRender(DrawingContext drawingContext)
{
    var rtb = new RenderTargetBitmap((int)ActualWidth, (int)ActualHeight, 96, 96, PixelFormats.Pbgra32);
    var line = new Line();
    RenderOptions.SetEdgeMode(line, EdgeMode.Aliased);
    line.Stroke = Brushes.Black;
    line.StrokeThickness = 1;
    line.X1 = 0;
    line.X2 = ActualWidth;
    line.Y1 = 0;
    line.Y2 = ActualHeight;
    line.Arrange(new Rect(new Size((int)ActualWidth, (int)ActualHeight)));
    rtb.Render(line);
    drawingContext.DrawImage(rtb, new Rect(0, 0, (int)ActualWidth, (int)ActualHeight));
}

这个"解决方案"至少可以说是令人讨厌的。这真的很糟糕,但与我迄今为止从WPF看到的其他方法相比,这可能是一种合法的方法。然而,我将为一些进一步的答案留下话题。

为什么最小化和恢复窗口会对WPF中已经绘制的图形产生影响

我想这是因为你在使用

SnapsToDevicePixels="True" 

根据微软msdn

,像素捕捉并不总是精确的

遗憾的是,仅仅调整容器对象的大小并不能保证设备像素对齐。应用程序的整个布局可能会影响图像的对齐。每英寸显示点(dpi)也影响图像对齐。在上面的例子中,只有当显示器设置为每英寸96点(dpi)时,图像对齐才能工作。在任何其他设置中,需要调整布局以适应显示设置。在Windows Presentation Foundation (WPF)应用程序中应尽可能避免高频图像。

试着把这个标志改为false看看效果如何