WPF 的 VisualBrush 只刷新显示的视觉效果,不刷新布局范围

Posted lonelyxmas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF 的 VisualBrush 只刷新显示的视觉效果,不刷新布局范围相关的知识,希望对你有一定的参考价值。

原文:WPF 的 VisualBrush 只刷新显示的视觉效果,不刷新布局范围

WPF 的 VisualBrush 可以帮助我们在一个控件中显示另一个控件的外观。这是非常妙的功能。

但是本文需要说其中的一个 Bug —— 如果使用 VisualBrush 显示另一个控件的外观,那么只会在其显示效果有改变的时候刷新,而不会在目标布局改变的时候刷新布局。


用于复现问题的代码

我们现在做一个可以用于验证此问题的布局。

在一个大的 Grid 容器中有一个 Grid 和一个 Border,这个 Grid 将放一个大面积的 Rectangle 和一个表示内容的 TextBlock;而那个 Border 将完全以 VisualBrush 的形式呈现,呈现的内容是此 Grid 中的全部内容。

技术图片

它的完整 XAML 代码如下:

<Window x:Class="Walterlv.Demo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Walterlv 的 WindowChrome 示例窗口" Height="450" Width="800"
        WindowStartupLocation="CenterScreen">
    <Grid>
        <Grid x:Name="VisualSource">
            <Rectangle x:Name="VisibleOr" Fill="LightCoral" Visibility="Visible" />
            <TextBlock FontSize="24" TextAlignment="Center" VerticalAlignment="Center">
                <Run Text="Im walterlv, " />
                <LineBreak />
                <Run Text="Im reproducing this Visual bug." />
            </TextBlock>
        </Grid>
        <Border>
            <Border.Background>
                <VisualBrush Visual="{Binding Source={x:Reference VisualSource}}" />
            </Border.Background>
        </Border>
    </Grid>
</Window>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

其后台 C# 代码如下,包含每隔 1 秒钟切换 Rectangle 可见性的代码。

using System.Threading.Tasks;
using System.Windows;

namespace Walterlv.Demo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += OnLoaded;
        }

        private async void OnLoaded(object sender, RoutedEventArgs e)
        {
            while (true)
            {
                await Task.Delay(1000);
                VisibleOr.Visibility = Visibility.Collapsed;
                await Task.Delay(1000);
                VisibleOr.Visibility = Visibility.Visible;
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

验证问题

我们知道,VisualBrush 在默认情况下会将 Visual 中的全部内容拉伸到控件中显示,于是可以预估出两个可能的结果:

  • 如果 Rectangle 可见(VisibilityVisible),那么 Border 中以 VisualBrush 显示的内容将完全和下面重叠(因为大小相同,拉伸后正好重叠)。
  • 如果 Rectangle 不可见(VisibilityCollapsed),那么 Border 中以 VisualBrush 显示的内容将仅有文字且拉伸到整个 Border 范围。

然而实际运行真的是这样子吗?

下面的动图是 Rectangle 初始状态可见时,窗口运行后的结果:

技术图片

下面的动图是 Rectangle 初始状态不可见时,窗口运行后的结果:

技术图片

注意到了吗?

只有初始状态才能正确反应我们之前预估出的结果,而无论后面怎么再改变可见性,布局都不会再刷新了。只是——后面 VisualBrush 的内容始终重叠。这意味着 VisualBrush 中目标 Visual 的范围增大之后不会再缩小了。

问题?

这是问题吗?

于是在以下 issue 中跟进此问题:

VisualBrush 的其他 Bug

参见:


我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

技术图片

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

发布了382 篇原创文章 · 获赞 232 · 访问量 47万+

以上是关于WPF 的 VisualBrush 只刷新显示的视觉效果,不刷新布局范围的主要内容,如果未能解决你的问题,请参考以下文章

关于wpf窗体编程的问题~ 在使用visualBrush进行字体上下镜像对称出现时,如下图所示:

WPF 如何获取有哪些 VisualBrush 用了某个控件

WPF - 带OpacityMask / VisualBrush的边框:内存泄漏

wpf 容器截图

WPF设计の不规则窗体

在WPF中使用另一个控件作为不透明蒙板?