防止WPF窗口闪烁

4

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

问题在于它看起来很糟糕。

这是我现在正在做的:

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);
    }
}

以下是慢动作效果:
the window flickers

为了解决这个问题,我尝试了几种方法。但每种方法似乎只适用于Winforms。
例如,我遵循了Bee Eee的这篇博客文章来禁用绘图和锁定窗口更新,但都没有成功。

我还尝试重写此帖子中所见的WM_PAINT消息,但卡在了捕捉消息后该怎么做上。行:base.WndProc (ref msg); 抛出错误 "'System.Windows.Window' does not contain a definition for 'WndProc'"

当然,那段代码是针对Winforms的,而我正在使用描述在WPF中如何处理WndProc消息中的hwndSource.AddHook方法...



由于我的自定义按钮,我的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, 我不知道如何“隐藏”列,我只是将其宽度设置为0。但更大的问题似乎是我需要调整包含它的窗口的大小和位置。



@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);

这是结果:
秒表结果

1
我可以帮助展示你的XAML。你考虑过将元素放在一个宽度设置为自动的网格列中,然后在该列中显示/隐藏内容吗? - Walt Ritscher
调整窗口大小可能会导致视觉树的完全重绘/重新布局,这可能非常昂贵。有没有办法保持窗口大小? - Emond
听起来相当可怕。你尝试使用性能工具来测量调整大小期间大部分时间花费在哪里了吗? - Emond
@ErnodeWeerd 显然改变宽度需要最多的时间。 - Scott Solmer
@o_weisman 谢谢你提供的链接。不幸的是,他们基本上说我需要做的事情无法完成。我需要调整实际窗口的大小,而不仅仅是在透明窗口中更改其大小。用户必须能够与被释放空间后面的任何内容进行交互。但我对 Tim Dawson 所说的“使用反射来访问 Window 类的内部成员”很感兴趣。 - Scott Solmer
显示剩余12条评论
1个回答

2
你可以在网格中使用透明窗口(AllowTransparency = True),然后当你的控件需要隐藏时,你可以将控件的可见性设置为collapsed。这样就不会出现闪烁和窗口移动,但是也不会有任何东西,所以你会看到像调整大小、移动窗口一样的效果。

这个可行!具体来说,我正在使用 btnScrollLeft.Visibility = System.Windows.Visibility.Hidden;btnScrollLeft.Visibility = System.Windows.Visibility.Visible; 这两句代码的效果就像是调整窗口大小一样。按钮后面的区域不会捕获鼠标事件,用户可以与其背后的任何内容进行交互。 - Scott Solmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接