Skip to content

窗口隐藏(Visibility.Hidden)期间实例化的 hc:Divider 分隔线渲染宽度为 0 #1818

Description

@ABA2396

Describe the bug

当宿主窗口处于 Visibility.Hidden 状态(典型的 「最小化到托盘」 场景)时,如果有 hc:Divider(或任何以 hc:Row/hc:Col 为模板根的控件)的模板在此期间被实例化并加入可视化树,这些元素会永久渲染失败:

  • Divider 控件本身能拿到正常的布局尺寸(例如 420×15);
  • 但其模板内的三个 hc:Col(左线 / 内容 / 右线)的 ActualWidth/ActualHeight 均保持 0,视觉上完全不显示;
  • 窗口恢复 Visible 后不会自愈,手动调用 InvalidateMeasure / InvalidateArrange / UpdateLayout 也无法恢复;
  • 使用标准 Grid/Border 模板的元素在同样时序下显示正常,因此该问题特定于 Row/Col 栅格。

Steps to reproduce the bug

最小复现工程

DividerTest.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net10.0-windows10.0.17763.0</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWPF>true</UseWPF>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="HandyControl" Version="3.6.0-rc3" />
  </ItemGroup>
</Project>

App.xaml

<Application x:Class="DividerTest.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml" />
                <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

MainWindow.xaml

<Window x:Class="DividerTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:hc="https://handyorg.github.io/handycontrol"
        Title="Divider repro" Width="900" Height="600">
    <Window.Resources>
        <DataTemplate x:Key="LogTemplate">
            <hc:Divider MaxWidth="420" HorizontalContentAlignment="Center"
                        Content="{Binding}" />
        </DataTemplate>
    </Window.Resources>
    <ScrollViewer HorizontalScrollBarVisibility="Disabled">
        <ItemsControl x:Name="LogList" ItemTemplate="{StaticResource LogTemplate}" />
    </ScrollViewer>
</Window>

MainWindow.xaml.cs

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

namespace DividerTest;

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();

        // 1s 后添加第一个 divider,随即最小化并隐藏窗口(模拟最小化到托盘)
        var t1 = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
        t1.Tick += (s, e) =>
        {
            t1.Stop();
            LogList.Items.Add("A: 添加后立即隐藏");
            WindowState = WindowState.Minimized;
            ShowInTaskbar = false;
            Visibility = Visibility.Hidden;

            // 2s 后(窗口仍隐藏)再添加一个
            var t2 = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
            t2.Tick += (s2, e2) =>
            {
                t2.Stop();
                LogList.Items.Add("B: 隐藏期间添加");

                // 2s 后恢复窗口
                var t3 = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
                t3.Tick += (s3, e3) =>
                {
                    t3.Stop();
                    Show();
                    WindowState = WindowState.