Skip to content

Commit 91c5efc

Browse files
authored
workaround for regressions caused by ItemsPanelRoot resolution timing (#1294)
1 parent 71fc2e4 commit 91c5efc

File tree

4 files changed

+56
-22
lines changed

4 files changed

+56
-22
lines changed

src/Uno.Toolkit.UI/Controls/Chips/ChipGroup.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using System.Collections.Generic;
44
using System.Linq;
55
using System.Text;
6+
using Uno.UI.Extensions;
7+
68

79
#if IS_WINUI
810
using Microsoft.UI.Xaml;
@@ -18,7 +20,6 @@ namespace Uno.Toolkit.UI
1820
{
1921
public partial class ChipGroup : ItemsControl
2022
{
21-
private bool _isLoaded;
2223
private bool _isSynchronizingSelection;
2324

2425
public ChipGroup()
@@ -31,11 +32,26 @@ public ChipGroup()
3132
protected override void OnApplyTemplate()
3233
{
3334
base.OnApplyTemplate();
35+
36+
// workaround for #1287 ItemsPanelRoot resolution timing related issue
37+
var presenter =
38+
this.GetTemplateRoot() as ItemsPresenter ??
39+
this.GetFirstDescendant<ItemsPresenter>();
40+
if (presenter is { })
41+
{
42+
presenter.Loaded += OnItemsPresenterLoaded;
43+
}
3444
}
3545

3646
private void OnLoaded(object sender, RoutedEventArgs e)
3747
{
38-
_isLoaded = true;
48+
SynchronizeInitialSelection();
49+
EnforceSelectionMode();
50+
ApplyIconTemplate(null, IconTemplate);
51+
}
52+
53+
private void OnItemsPresenterLoaded(object sender, RoutedEventArgs e)
54+
{
3955
SynchronizeInitialSelection();
4056
EnforceSelectionMode();
4157
ApplyIconTemplate(null, IconTemplate);
@@ -58,6 +74,7 @@ private void OnSelectionMemberPathChanged(DependencyPropertyChangedEventArgs e)
5874

5975
private void ApplyIconTemplate(DataTemplate? oldTemplate, DataTemplate? newTemplate)
6076
{
77+
if (!IsReady) return;
6178
if (oldTemplate == newTemplate) return;
6279

6380
foreach (var container in this.GetItemContainers<Chip>())
@@ -403,7 +420,7 @@ bool ShouldClearSelection(Chip container)
403420
}
404421
}
405422

406-
private bool IsReady => _isLoaded && HasItems && HasContainers;
423+
private bool IsReady => IsLoaded && HasItems && HasContainers;
407424

408425
private bool HasItems => this.GetItems().OfType<object>().Any();
409426

src/Uno.Toolkit.UI/Controls/TabBar/TabBar.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ private void OnLoaded(object sender, RoutedEventArgs e)
195195
UpdateOrientation();
196196
}
197197

198+
internal void OnItemsPanelConnected(TabBarListPanel panel)
199+
{
200+
System.Diagnostics.Debug.Assert(ItemsPanelRoot != null, "ItemsPanelRoot is expected to be already set in here.");
201+
202+
SynchronizeInitialSelection();
203+
UpdateOrientation();
204+
}
205+
198206
private void OnTabBarItemClick(object sender, RoutedEventArgs e)
199207
{
200208
if (_isSynchronizingSelection)
@@ -441,7 +449,7 @@ private void RaiseSelectionChangedEvent(object? prevItem, object? nextItem)
441449
return null;
442450
}
443451

444-
private bool IsReady => _isLoaded && HasItems;
452+
private bool IsReady => _isLoaded && HasItems && ItemsPanelRoot is { };
445453

446454
private bool HasItems => this.GetItems().Any();
447455
}

src/Uno.Toolkit.UI/Controls/TabBar/TabBarListPanel.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,40 @@ namespace Uno.Toolkit.UI
1717
{
1818
public partial class TabBarListPanel : Panel
1919
{
20-
public Orientation Orientation
21-
{
22-
get { return (Orientation)GetValue(OrientationProperty); }
23-
set { SetValue(OrientationProperty, value); }
24-
}
20+
#region DependencyProperty: Orientation
2521

2622
public static DependencyProperty OrientationProperty { get; } = DependencyProperty.Register(
2723
nameof(Orientation),
2824
typeof(Orientation),
2925
typeof(TabBarListPanel),
30-
new PropertyMetadata(Orientation.Horizontal, (s, e) => ((TabBarListPanel)s).OnPropertyChanged(e)));
26+
new PropertyMetadata(default(Orientation), OnOrientationChanged));
27+
28+
public Orientation Orientation
29+
{
30+
get => (Orientation)GetValue(OrientationProperty);
31+
set => SetValue(OrientationProperty, value);
32+
}
33+
34+
#endregion
35+
36+
public TabBarListPanel()
37+
{
38+
this.Loaded += OnLoaded;
39+
}
40+
41+
private void OnLoaded(object sender, RoutedEventArgs e)
42+
{
43+
var owner = this.FindFirstParent<TabBar>();
44+
45+
// workaround for #1287 ItemsPanelRoot resolution timing related issue
46+
owner?.OnItemsPanelConnected(this);
47+
}
3148

32-
private void OnPropertyChanged(DependencyPropertyChangedEventArgs args)
49+
private static void OnOrientationChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
3350
{
34-
if (args.Property == OrientationProperty)
51+
if (sender is TabBar owner)
3552
{
36-
InvalidateMeasure();
53+
owner.InvalidateMeasure();
3754
}
3855
}
3956

@@ -132,6 +149,6 @@ protected override Size ArrangeOverride(Size finalSize)
132149
return finalSize;
133150
}
134151

135-
private bool IsVisible(UIElement x) => x.Visibility == Visibility.Visible;
152+
private static bool IsVisible(UIElement x) => x.Visibility == Visibility.Visible;
136153
}
137154
}

src/Uno.Toolkit.UI/Extensions/ItemsControlExtensions.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,6 @@ item as T ??
5656
/// <remarks>An empty enumerable will returned if the <see cref="ItemsControl.ItemsPanelRoot"/> and the containers have not been materialized.</remarks>
5757
public static IEnumerable<T> GetItemContainers<T>(this ItemsControl itemsControl) =>
5858
itemsControl.ItemsPanelRoot?.Children.OfType<T>() ??
59-
// #1281 workaround: ItemsPanelRoot would not be resolved until ItemsPanel is loaded,
60-
// which will be the case between the ItemsControl::Loaded and ItemsPanel::Loaded.
61-
// This is normally not a problem, as the container is typically created after that with ItemsSource.
62-
// However, for xaml-defined items, this could cause a problem with initial selection synchronization,
63-
// which happens on ItemsControl::Loaded. For this case, we will resort to using ItemsControl::Items.
64-
(itemsControl.ItemsSource is null && itemsControl.Items is { }
65-
? itemsControl.Items.OfType<T>()
66-
: null) ??
6759
Enumerable.Empty<T>();
6860

6961
/// <summary>

0 commit comments

Comments
 (0)