防止 WPF 窗口闪烁

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22563416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 11:17:42  来源:igfitidea点击:

Prevent WPF window flicker

c#wpfpaintflickersuspend

提问by Scott Solmer

I've got a borderless WPF window that needs to be able to hide one of its controls and shrink the window at the same time.

我有一个无边框 WPF 窗口,它需要能够隐藏其中一个控件并同时缩小窗口。

The problem is that it looks terrible.

问题是它看起来很糟糕。

Here's what I am doing now:

这是我现在正在做的事情:

private void btnShowHideTopBar_Click(object sender, RoutedEventArgs e)
{
    if (commandTopHide == true)
    {
        txtblkShowHideTopBar.Text = "Show Top Bar";
        commandTopHide = false;
        myWindow.Left = 1100;
        myWindow.Width = 180;
        RSide.Width = new GridLength(0, GridUnitType.Pixel);
    }
    else if (commandTopHide == false)
    {
        txtblkShowHideTopBar.Text = "Hide Top Bar";
        commandTopHide = true;
        myWindow.Left = 1030;
        myWindow.Width = 250;
        RSide.Width = new GridLength(70, GridUnitType.Pixel);
    }
}

And here is what it looks like in slow motion:
the window flickers

这是慢动作的样子:
窗户在闪烁

To correct this, I have tried a few things. Each of which apparently only apply to Winforms.
For example, I followed this blog post at Bee Eeeto disable drawing and 'lock window update' to no avail.

为了纠正这个问题,我尝试了一些事情。其中每一个显然只适用于 Winforms。
例如,我在 Bee Eee上关注了这篇博客文章以禁用绘图和“锁定窗口更新”,但无济于事。

I've also tried overriding the WM_PAINT message as seen in this postbut I got stuck on what to do with the message once I catch it. The line base.WndProc(ref msg);throws the error "'System.Windows.Window' does not contain a definition for 'WndProc'"

我也试过覆盖 WM_PAINT 消息,如本文所示,但一旦我发现该消息,我就被困在如何处理该消息上。该行base.WndProc(ref msg);抛出错误“ 'System.Windows.Window'不包含'WndProc'的定义

Granted, that code was for Winforms and I am using the hwndSource.AddHookmethod as described in How to handle WndProc messages in WPF?)...

当然,该代码适用于 Winforms,我正在使用如何在 WPF 中处理 WndProc 消息中hwndSource.AddHook描述的方法)...





My xaml is fairly massive due to a my custom buttons, so I'll leave that out. Here is what's left:

由于我的自定义按钮,我的 xaml 相当大,所以我会忽略它。这是剩下的:

<Window x:Name="myWindow" x:Class="myNamespace.myWindowClass"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
    Title="WiMan" Height="210" Width="250" ResizeMode="NoResize" WindowStyle="None" MinWidth="180" 
    MinHeight="210" MaxWidth="250" MaxHeight="210" Left="1030" Top="66" Loaded="ControlBoxLoadEvent" 
    Icon="pack://siteoforigin:,,,/Resources/App.ico" Closing="MainWindowIsClosing" Foreground="White" 
    Background="{x:Null}" AllowsTransparency="True">
<Window.Resources>
    <ControlTemplate ...stuff I left out.. > lots of stuff... </ControlTemplate>
</Window.Resources>
<Grid x:Name="MainWindowGrid" RenderTransformOrigin="0.5,0.5">
    <Grid.Background>
        <LinearGradientBrush EndPoint="160,240" StartPoint="160,-20" MappingMode="Absolute">
            <LinearGradientBrush.RelativeTransform>
                <TransformGroup>
                    <ScaleTransform CenterY="0.5" CenterX="0.5" ScaleY="1" ScaleX="1"/>
                    <SkewTransform AngleY="0" AngleX="0" CenterY="0.5" CenterX="0.5"/>
                    <RotateTransform Angle="-4.764" CenterY="0.5" CenterX="0.5"/>
                    <TranslateTransform/>
                </TransformGroup>
            </LinearGradientBrush.RelativeTransform>
            <GradientStop Color="#FF1B1B1B" Offset="1"/>
            <GradientStop Color="#7FC3C3C3"/>
        </LinearGradientBrush>
    </Grid.Background>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Name="RSide" Width="70"/>
        <ColumnDefinition Width="84*"/>
        <ColumnDefinition Width="83*"/>
    </Grid.ColumnDefinitions>
    <Button x:Name="btnShowHideTopBar" FontFamily="Arial Rounded MT Bold" FontSize="18" Click="btnShowHideTopBar_Click" 
      Template="...the stuff I left out..." Foreground="White" Background="{x:Null}" BorderBrush="{x:Null}" Margin="2" Grid.Row="1" Grid.Column="1">
        <TextBlock x:Name="txtblkShowHideTopBar" TextWrapping="Wrap" Text="Hide Topbar" TextAlignment="Center"/>
    </Button>
    <Button x:Name="btnShowHideSideBar" Grid.Column="2" Grid.Row="1" FontFamily="Arial Rounded MT Bold" FontSize="18" Click="eventHideShowSideBar_Click" 
     Template="...the stuff I left out..." Foreground="White" Background="{x:Null}" BorderBrush="{x:Null}" Margin="2">
        <TextBlock x:Name="txtblkShowHideSideBar" TextWrapping="Wrap" Text="Hide Sidebar" TextAlignment="Center"/>
    </Button>
    <Button Content="Configure" Click="btnConfigure_Click" FontFamily="Arial Rounded MT Bold" FontSize="18" 
     Template="...the stuff I left out..." Foreground="White" Background="{x:Null}" BorderBrush="{x:Null}" Margin="2" Grid.ColumnSpan="2" Grid.Column="1"/>
    <Grid Grid.RowSpan="2">
        <Grid.Background>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FF3C8AE8" Offset="0"/>
                <GradientStop Color="#FF032440" Offset="1"/>
            </LinearGradientBrush>
        </Grid.Background>
    </Grid>
    <Button x:Name="btnScrollLeft" Content="R Side" Click="RSideScrollButton_Click" FontFamily="Arial Rounded MT Bold" FontSize="18" 
      Template="...the stuff I left out..." Foreground="White" Background="{x:Null}" BorderBrush="{x:Null}" Margin="3,2,3,3" Grid.RowSpan="2"/>
</Grid>

@Walt Ritscher, I don't know about 'hiding' the column, I'm just setting it's width to 0. But the bigger problem seems to be that I need to resize and reposition the window that contains it.

@Walt Ritscher,我不知道“隐藏”列,我只是将它的宽度设置为 0。但更大的问题似乎是我需要调整包含它的窗口的大小和位置。





@ErnodeWeerd, I've implemented a stopwatch as you can see here:

@ErnodeWeerd,我已经实现了一个秒表,你可以在这里看到:

    Stopwatch s = new Stopwatch();
    string a; string b; string c; 

    s.Start();
    myWindow.Left = 1100;
    s.Stop(); a = s.Elapsed.ToString(); s.Reset();

    s.Start();
    myWindow.Width = 180;
    s.Stop(); b = s.Elapsed.ToString(); s.Reset();

    s.Start();
    RSide.Width = new GridLength(0, GridUnitType.Pixel);
    s.Stop(); c = s.Elapsed.ToString(); s.Reset();

    MessageBox.Show(a + Environment.NewLine +
            b + Environment.NewLine +
            c + Environment.NewLine);

This is the result:
stopwatch result

这是结果:
秒表结果

采纳答案by woutervs

You can use a transparent window (AllowTransparency = True) with a grid, then when your control needs to be hidden you can set the visibility of the control to collapsed. There will be no flickering and no moving of the window but there won't be anything there either so you will see throug as if you would have resized, moved your window.

您可以使用带有网格的透明窗口 (AllowTransparency = True),然后当您的控件需要隐藏时,您可以将控件的可见性设置为折叠。窗口不会闪烁,也不会移动,但那里也不会有任何东西,因此您会看到整个画面,就好像您会调整大小、移动窗口一样。