fix: Row fails to arrange Cols when the template is instantiated while the hosting window is hidden - #1819
Open
ABA2396 wants to merge 1 commit into
Open
Conversation
…e the hosting window is hidden
Author
|
fix #1818 |
ABA2396
added a commit
to MaaAssistantArknights/MaaAssistantArknights
that referenced
this pull request
Aug 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
当
hc:Divider(或任何以hc:Row/hc:Col为模板根的控件)的模板在 「存在Hidden祖先」 的状态下被实例化时(最典型的是 「最小化到托盘」 场景:宿主窗口WindowState = Minimized+Visibility = Hidden;Divider自身或任何祖先为Hidden时同理),该元素会永久渲染失败:hc:Col子元素ActualWidth/ActualHeight永久保持 0,分隔线与内容完全不显示;Visible后不会自愈,手动调用InvalidateMeasure/InvalidateArrange/UpdateLayout均无效。而使用标准
Grid/Border模板的元素在相同时序下完全正常,因此该问题特定于Row/Col栅格。根因
Row.ArrangeOverride使用child.IsVisible决定是否跳过Col:IsVisible是综合考虑整条祖先链(包括宿主窗口)的运行时可见性——窗口Hidden期间实例化的模板子树在布局过程中IsVisible == false,导致这些Col被跳过、从未被Arrange。窗口恢复可见后,被跳过Arrange的Col布局状态无法再恢复,ActualWidth/ActualHeight永久为 0(Measure阶段是正常的,DesiredSize与可见时添加的完全一致,仅Arrange失败)。该状态没有任何自愈路径——实测以下手段全部无效:
Col.IsVisible实际已变回true,但Actual仍为 0×0;Divider祖先链调用InvalidateMeasure/InvalidateArrange/UpdateLayout;Col自身调用InvalidateMeasure/InvalidateArrange/UpdateLayout;Divider自身Visibility从Hidden改回Visible,或先改为Collapsed再改回Visible。(对比:
Collapsed场景天然不触发本 bug——Collapsed子树不参与布局、模板不会实例化,恢复Visible时才首次展开,首次布局即正常,见下方差异分析。)修复
将该检查改为读取元素自身的
Visibility属性(不受祖先窗口隐藏状态影响):foreach (var child in cols) { - if (!child.IsVisible) + // Check the local Visibility, not IsVisible: Cols skipped while the hosting + // window is hidden can never recover their layout once it is shown again. + if (child.Visibility != Visibility.Visible) { continue; }行为差异分析(相对原实现):
IsVisible)Visibility)Col自身Collapsed或HiddenCollapsedVisible时才首次展开,首次布局即正常Hidden祖先(Divider自身Hidden、宿主窗口Hidden等,Col自身Visible)Hidden期间实例化,Col被跳过且事后无法自愈(本 bug)关键在于 WPF 两种 「不可见」 的语义差异:
Collapsed的子树不参与布局、模板不会实例化,恢复Visible时是 「首次布局 + 模板首次展开」,天然不触发本 bug;而Hidden参与布局,模板照常实例化,Col会在IsVisible == false的布局轮次中被跳过Arrange。实测(NuGet 3.6.0-rc3,窗口始终可见):Divider自身或祖先为Collapsed时恢复后Line ActualW = 138.7 / 124.5(正常);Divider自身Hidden期间实例化、改回Visible后Line ActualW仍为0.0——与宿主窗口Hidden场景症状完全一致。验证
复现工程(net10.0-windows + HandyControl):窗口隐藏期间向
ItemsControl添加使用hc:Divider的 item,2 秒后恢复窗口,读取可视化树:修复前(NuGet 3.5.1 / 3.6.0-rc3,两者均复现):
修复后(本分支源码构建的 HandyControl.dll 直接替换验证):
完整复现工程与运行截图见 issue。