From 55706e68f0056b9307f03141dd59627d81724e3b Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Thu, 7 Mar 2024 13:25:03 +0800 Subject: [PATCH 1/2] use self impl EqualPanel to fix layout cycle --- src/Snap.Hutao/Snap.Hutao/App.xaml | 1 + .../Snap.Hutao/Control/Panel/EqualPanel.cs | 89 ++++++++++++++ .../Control/Panel/PanelSelector.xaml | 1 + .../Control/Theme/SegmentedOverride.xaml | 115 ++++++++++++++++++ src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj | 6 + .../View/Control/StatisticsSegmented.xaml | 1 + 6 files changed, 213 insertions(+) create mode 100644 src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Control/Theme/SegmentedOverride.xaml diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml b/src/Snap.Hutao/Snap.Hutao/App.xaml index eca83605..3cda18bc 100644 --- a/src/Snap.Hutao/Snap.Hutao/App.xaml +++ b/src/Snap.Hutao/Snap.Hutao/App.xaml @@ -23,6 +23,7 @@ + diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs b/src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs new file mode 100644 index 00000000..d3f6c68f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs @@ -0,0 +1,89 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.UI.Xaml; +using System.Data; +using Windows.Foundation; + +namespace Snap.Hutao.Control.Panel; + +[DependencyProperty("Spacing", typeof(double), default(double), nameof(OnSpacingChanged))] +internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel +{ + private double maxItemWidth; + private double maxItemHeight; + private int visibleItemsCount; + + public EqualPanel() + { + RegisterPropertyChangedCallback(HorizontalAlignmentProperty, OnHorizontalAlignmentChanged); + } + + protected override Size MeasureOverride(Size availableSize) + { + maxItemWidth = 0; + maxItemHeight = 0; + + IEnumerable elements = Children.Where(static e => e.Visibility == Visibility.Visible); + visibleItemsCount = elements.Count(); + + foreach (UIElement child in elements) + { + child.Measure(availableSize); + maxItemWidth = Math.Max(maxItemWidth, child.DesiredSize.Width); + maxItemHeight = Math.Max(maxItemHeight, child.DesiredSize.Height); + } + + if (visibleItemsCount > 0) + { + // Return equal widths based on the widest item + // In very specific edge cases the AvailableWidth might be infinite resulting in a crash. + if (HorizontalAlignment != HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width)) + { + return new Size((maxItemWidth * visibleItemsCount) + (Spacing * (visibleItemsCount - 1)), maxItemHeight); + } + else + { + // Equal columns based on the available width, adjust for spacing + double totalWidth = availableSize.Width - (Spacing * (visibleItemsCount - 1)); + maxItemWidth = totalWidth / visibleItemsCount; + return new Size(availableSize.Width, maxItemHeight); + } + } + else + { + return new Size(0, 0); + } + } + + protected override Size ArrangeOverride(Size finalSize) + { + double x = 0; + + // Check if there's more (little) width available - if so, set max item width to the maximum possible as we have an almost perfect height. + if (finalSize.Width > (visibleItemsCount * maxItemWidth) + (Spacing * (visibleItemsCount - 1))) + { + maxItemWidth = (finalSize.Width - (Spacing * (visibleItemsCount - 1))) / visibleItemsCount; + } + + IEnumerable elements = Children.Where(static e => e.Visibility == Visibility.Visible); + foreach (UIElement child in elements) + { + child.Arrange(new Rect(x, 0, maxItemWidth, maxItemHeight)); + x += maxItemWidth + Spacing; + } + + return finalSize; + } + + private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + EqualPanel panel = (EqualPanel)d; + panel.InvalidateMeasure(); + } + + private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp) + { + InvalidateMeasure(); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml b/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml index 8304b0b1..ba913e4e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml +++ b/src/Snap.Hutao/Snap.Hutao/Control/Panel/PanelSelector.xaml @@ -6,6 +6,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:shcm="using:Snap.Hutao.Control.Markup" + Style="{StaticResource DefaultSegmentedStyle}" mc:Ignorable="d"> + + + + + + + + + 1 + + + + + 1 + + + + + 1 + + + + 1 + 2 + + + + + + + \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index bd6cc9cd..be4d16e4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -156,6 +156,7 @@ + @@ -348,6 +349,11 @@ + + + MSBuild:Compile + + MSBuild:Compile diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsSegmented.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsSegmented.xaml index d5d4d5ac..1857bace 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsSegmented.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/StatisticsSegmented.xaml @@ -6,6 +6,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:shcm="using:Snap.Hutao.Control.Markup" + Style="{StaticResource DefaultSegmentedStyle}" mc:Ignorable="d"> From 4aa95575266cc1644dce897107908a0715828307 Mon Sep 17 00:00:00 2001 From: Lightczx <1686188646@qq.com> Date: Thu, 7 Mar 2024 16:20:10 +0800 Subject: [PATCH 2/2] code style --- .../Snap.Hutao/Control/Panel/EqualPanel.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs b/src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs index d3f6c68f..ebf1e140 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Panel/EqualPanel.cs @@ -3,6 +3,7 @@ using Microsoft.UI.Xaml; using System.Data; +using System.Runtime.InteropServices; using Windows.Foundation; namespace Snap.Hutao.Control.Panel; @@ -24,10 +25,10 @@ internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel maxItemWidth = 0; maxItemHeight = 0; - IEnumerable elements = Children.Where(static e => e.Visibility == Visibility.Visible); - visibleItemsCount = elements.Count(); + List elements = [.. Children.Where(element => element.Visibility == Visibility.Visible)]; + visibleItemsCount = elements.Count; - foreach (UIElement child in elements) + foreach (ref readonly UIElement child in CollectionsMarshal.AsSpan(elements)) { child.Measure(availableSize); maxItemWidth = Math.Max(maxItemWidth, child.DesiredSize.Width); @@ -38,7 +39,7 @@ internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel { // Return equal widths based on the widest item // In very specific edge cases the AvailableWidth might be infinite resulting in a crash. - if (HorizontalAlignment != HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width)) + if (HorizontalAlignment is not HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width)) { return new Size((maxItemWidth * visibleItemsCount) + (Spacing * (visibleItemsCount - 1)), maxItemHeight); } @@ -78,8 +79,7 @@ internal partial class EqualPanel : Microsoft.UI.Xaml.Controls.Panel private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - EqualPanel panel = (EqualPanel)d; - panel.InvalidateMeasure(); + (d as EqualPanel)?.InvalidateMeasure(); } private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp)