Skip to content

Commit 1424da1

Browse files
committed
Revert "Code Quality: Removed ISidebarItemModel 2 (#18061)"
This reverts commit 3e1fb20.
1 parent 99d6199 commit 1424da1

File tree

8 files changed

+134
-89
lines changed

8 files changed

+134
-89
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) Files Community
2+
// Licensed under the MIT License.
3+
4+
namespace Files.App.Controls
5+
{
6+
public interface ISidebarItemModel : INotifyPropertyChanged
7+
{
8+
/// <summary>
9+
/// The children of this item that will be rendered as child elements of the SidebarItem
10+
/// </summary>
11+
object? Children { get; }
12+
13+
/// <summary>
14+
/// Determines whether the SidebarItem is expanded and the children are visible
15+
/// or if it is collapsed and children are not visible.
16+
/// </summary>
17+
bool IsExpanded { get; set; }
18+
19+
/// <summary>
20+
/// Indicates whether the children should have an indentation or not.
21+
/// </summary>
22+
bool PaddedItem { get; }
23+
}
24+
}

src/Files.App.Controls/Sidebar/SidebarItem.Properties.cs

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@
22
// Licensed under the MIT License.
33

44
using CommunityToolkit.WinUI;
5-
using System.Collections.Specialized;
65

76
namespace Files.App.Controls
87
{
98
public sealed partial class SidebarItem : Control
109
{
10+
public SidebarView? Owner
11+
{
12+
get { return (SidebarView?)GetValue(OwnerProperty); }
13+
set { SetValue(OwnerProperty, value); }
14+
}
15+
public static readonly DependencyProperty OwnerProperty =
16+
DependencyProperty.Register(nameof(Owner), typeof(SidebarView), typeof(SidebarItem), new PropertyMetadata(null));
17+
1118
public bool IsSelected
1219
{
1320
get { return (bool)GetValue(IsSelectedProperty); }
@@ -24,6 +31,14 @@ public bool IsExpanded
2431
public static readonly DependencyProperty IsExpandedProperty =
2532
DependencyProperty.Register(nameof(IsExpanded), typeof(bool), typeof(SidebarItem), new PropertyMetadata(true, OnPropertyChanged));
2633

34+
public bool IsInFlyout
35+
{
36+
get { return (bool)GetValue(IsInFlyoutProperty); }
37+
set { SetValue(IsInFlyoutProperty, value); }
38+
}
39+
public static readonly DependencyProperty IsInFlyoutProperty =
40+
DependencyProperty.Register(nameof(IsInFlyout), typeof(bool), typeof(SidebarItem), new PropertyMetadata(false));
41+
2742
public double ChildrenPresenterHeight
2843
{
2944
get { return (double)GetValue(ChildrenPresenterHeightProperty); }
@@ -33,6 +48,14 @@ public double ChildrenPresenterHeight
3348
public static readonly DependencyProperty ChildrenPresenterHeightProperty =
3449
DependencyProperty.Register(nameof(ChildrenPresenterHeight), typeof(double), typeof(SidebarItem), new PropertyMetadata(30d));
3550

51+
public ISidebarItemModel? Item
52+
{
53+
get { return (ISidebarItemModel)GetValue(ItemProperty); }
54+
set { SetValue(ItemProperty, value); }
55+
}
56+
public static readonly DependencyProperty ItemProperty =
57+
DependencyProperty.Register(nameof(Item), typeof(ISidebarItemModel), typeof(SidebarItem), new PropertyMetadata(null));
58+
3659
public bool UseReorderDrop
3760
{
3861
get { return (bool)GetValue(UseReorderDropProperty); }
@@ -71,52 +94,16 @@ public SidebarDisplayMode DisplayMode
7194
[GeneratedDependencyProperty]
7295
public partial object? ToolTip { get; set; }
7396

74-
[GeneratedDependencyProperty]
75-
public partial bool IsPaddedItem { get; set; }
76-
77-
[GeneratedDependencyProperty]
78-
public partial object? Children { get; set; }
79-
80-
[GeneratedDependencyProperty, Obsolete]
81-
public partial object? Item { get; set; }
82-
83-
[GeneratedDependencyProperty]
84-
public partial SidebarView? Owner { get; set; }
85-
86-
[GeneratedDependencyProperty]
87-
public partial bool IsInFlyout { get; set; }
88-
89-
partial void OnChildrenPropertyChanged(DependencyPropertyChangedEventArgs e)
97+
public static void SetTemplateRoot(DependencyObject target, FrameworkElement value)
9098
{
91-
if (e.OldValue is INotifyCollectionChanged oldNCC)
92-
oldNCC.CollectionChanged -= ChildItems_CollectionChanged;
93-
if (e.NewValue is INotifyCollectionChanged newNCC)
94-
newNCC.CollectionChanged += ChildItems_CollectionChanged;
99+
target.SetValue(TemplateRootProperty, value);
95100
}
96-
97-
partial void OnOwnerPropertyChanged(DependencyPropertyChangedEventArgs e)
98-
{
99-
if (Owner is null)
100-
return;
101-
102-
DisplayMode = Owner.DisplayMode;
103-
104-
Owner.RegisterPropertyChangedCallback(SidebarView.DisplayModeProperty, (sender, args) =>
105-
{
106-
DisplayMode = Owner.DisplayMode;
107-
});
108-
Owner.RegisterPropertyChangedCallback(SidebarView.SelectedItemProperty, (sender, args) =>
109-
{
110-
ReevaluateSelection();
111-
});
112-
113-
ReevaluateSelection();
114-
}
115-
116-
partial void OnIsInFlyoutPropertyChanged(DependencyPropertyChangedEventArgs e)
101+
public static FrameworkElement GetTemplateRoot(DependencyObject target)
117102
{
118-
VisualStateManager.GoToState(this, DisplayMode is SidebarDisplayMode.Compact && !IsInFlyout ? "Compact" : "NonCompact", true);
103+
return (FrameworkElement)target.GetValue(TemplateRootProperty);
119104
}
105+
public static readonly DependencyProperty TemplateRootProperty =
106+
DependencyProperty.Register("TemplateRoot", typeof(FrameworkElement), typeof(FrameworkElement), new PropertyMetadata(null));
120107

121108
public static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
122109
{

src/Files.App.Controls/Sidebar/SidebarItem.cs

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Microsoft.UI.Input;
66
using Microsoft.UI.Xaml.Automation;
77
using Microsoft.UI.Xaml.Automation.Peers;
8-
using Microsoft.UI.Xaml.Media;
98
using System.Collections.Specialized;
109
using Windows.ApplicationModel.DataTransfer;
1110

@@ -15,15 +14,16 @@ public sealed partial class SidebarItem : Control
1514
{
1615
private const double DROP_REPOSITION_THRESHOLD = 0.2; // Percentage of top/bottom at which we consider a drop to be a reposition/insertion
1716

18-
public bool HasChildren => Children is IList enumerable && enumerable.Count > 0;
19-
public bool IsGroupHeader => Children is not null;
17+
public bool HasChildren => Item?.Children is IList enumerable && enumerable.Count > 0;
18+
public bool IsGroupHeader => Item?.Children is not null;
2019
public bool CollapseEnabled => DisplayMode != SidebarDisplayMode.Compact;
2120

2221
private bool hasChildSelection => selectedChildItem != null;
2322
private bool isPointerOver = false;
2423
private bool isClicking = false;
2524
private object? selectedChildItem = null;
2625
private ItemsRepeater? childrenRepeater;
26+
private ISidebarItemModel? lastSubscriber;
2727

2828
public SidebarItem()
2929
{
@@ -50,13 +50,13 @@ protected override AutomationPeer OnCreateAutomationPeer()
5050

5151
internal void Select()
5252
{
53-
Owner?.SelectedItem = Item!;
53+
if (Owner is not null)
54+
Owner.SelectedItem = Item!;
5455
}
5556

5657
private void SidebarItem_Loaded(object sender, RoutedEventArgs e)
5758
{
58-
if (!IsInFlyout)
59-
Owner = this.FindAscendant<SidebarView>()!;
59+
HookupOwners();
6060

6161
if (GetTemplateChild("ElementBorder") is Border border)
6262
{
@@ -82,38 +82,56 @@ private void SidebarItem_Loaded(object sender, RoutedEventArgs e)
8282
flyoutRepeater.ElementPrepared += ChildrenPresenter_ElementPrepared;
8383
}
8484

85-
if (GetTemplateChild("ChildrenFlyout") is Flyout flyout)
86-
{
87-
flyout.Opened += ChildrenFlyout_Opened;
88-
}
89-
9085
HandleItemChange();
9186
}
9287

9388
public void HandleItemChange()
9489
{
90+
HookupItemChangeListener(null, Item);
9591
UpdateExpansionState();
9692
ReevaluateSelection();
9793
}
9894

99-
private void ChildrenFlyout_Opened(object? sender, object e)
95+
private void HookupOwners()
10096
{
101-
if (sender is not Flyout)
102-
return;
97+
FrameworkElement resolvingTarget = this;
98+
if (GetTemplateRoot(Parent) is FrameworkElement element)
99+
{
100+
resolvingTarget = element;
101+
}
102+
Owner = resolvingTarget.FindAscendant<SidebarView>()!;
103103

104-
var popup = VisualTreeHelper.GetOpenPopupsForXamlRoot(XamlRoot).ToList().FirstOrDefault();
105-
var itemsRepeater = popup?.Child.FindDescendant<ItemsRepeater>();
106-
if (itemsRepeater is null)
107-
return;
104+
Owner.RegisterPropertyChangedCallback(SidebarView.DisplayModeProperty, (sender, args) =>
105+
{
106+
DisplayMode = Owner.DisplayMode;
107+
});
108+
DisplayMode = Owner.DisplayMode;
108109

109-
var count = itemsRepeater.ItemsSourceView.Count;
110-
for (int i = 0; i < count; i++)
110+
Owner.RegisterPropertyChangedCallback(SidebarView.SelectedItemProperty, (sender, args) =>
111111
{
112-
if (itemsRepeater.GetOrCreateElement(i).FindDescendantOrSelf<SidebarItem>() is not { } sidebarItem)
113-
continue;
112+
ReevaluateSelection();
113+
});
114+
ReevaluateSelection();
115+
}
114116

115-
sidebarItem.Owner = Owner;
116-
sidebarItem.IsInFlyout = true;
117+
private void HookupItemChangeListener(ISidebarItemModel? oldItem, ISidebarItemModel? newItem)
118+
{
119+
if (lastSubscriber != null)
120+
{
121+
if (lastSubscriber.Children is INotifyCollectionChanged observableCollection)
122+
observableCollection.CollectionChanged -= ChildItems_CollectionChanged;
123+
}
124+
125+
if (oldItem != null)
126+
{
127+
if (oldItem.Children is INotifyCollectionChanged observableCollection)
128+
observableCollection.CollectionChanged -= ChildItems_CollectionChanged;
129+
}
130+
if (newItem != null)
131+
{
132+
lastSubscriber = newItem;
133+
if (newItem.Children is INotifyCollectionChanged observableCollection)
134+
observableCollection.CollectionChanged += ChildItems_CollectionChanged;
117135
}
118136
}
119137

@@ -124,7 +142,7 @@ private void SidebarItem_DragStarting(UIElement sender, DragStartingEventArgs ar
124142

125143
private void SetFlyoutOpen(bool isOpen = true)
126144
{
127-
if (Children is null) return;
145+
if (Item?.Children is null) return;
128146

129147
var flyoutOwner = (GetTemplateChild("ElementGrid") as FrameworkElement)!;
130148
if (isOpen)
@@ -157,7 +175,7 @@ private void ReevaluateSelection()
157175
Owner?.UpdateSelectedItemContainer(this);
158176
}
159177
}
160-
else if (Children is IList list)
178+
else if (Item?.Children is IList list)
161179
{
162180
if (list.Contains(Owner?.SelectedItem))
163181
{
@@ -176,7 +194,7 @@ private void ChildrenPresenter_ElementPrepared(ItemsRepeater sender, ItemsRepeat
176194
{
177195
if (args.Element is SidebarItem item)
178196
{
179-
if (Children is IList enumerable)
197+
if (Item?.Children is IList enumerable)
180198
{
181199
var newElement = enumerable[args.Index];
182200
if (newElement == selectedChildItem)
@@ -275,18 +293,20 @@ private void UpdatePointerState(bool isPointerDown = false)
275293

276294
private void UpdateExpansionState(bool useAnimations = true)
277295
{
278-
if (Children is null || !CollapseEnabled)
296+
if (Item?.Children is null || !CollapseEnabled)
279297
{
280-
VisualStateManager.GoToState(this, IsPaddedItem ? "NoExpansionWithPadding" : "NoExpansion", useAnimations);
298+
VisualStateManager.GoToState(this, Item?.PaddedItem == true ? "NoExpansionWithPadding" : "NoExpansion", useAnimations);
281299
}
282300
else if (!HasChildren)
283301
{
284302
VisualStateManager.GoToState(this, "NoChildren", useAnimations);
285303
}
286304
else
287305
{
288-
if (Children is IList { Count: > 0 } enumerable && childrenRepeater?.ItemsSourceView.Count > 0 && childrenRepeater?.GetOrCreateElement(0) is UIElement firstChild)
306+
if (Item?.Children is IList enumerable && enumerable.Count > 0 && childrenRepeater is not null)
289307
{
308+
var firstChild = childrenRepeater.GetOrCreateElement(0);
309+
290310
// Collapsed elements might have a desired size of 0 so we need to have a sensible fallback
291311
var childHeight = firstChild.DesiredSize.Height > 0 ? firstChild.DesiredSize.Height : 32;
292312
ChildrenPresenterHeight = enumerable.Count * childHeight;

src/Files.App.Controls/Sidebar/SidebarItemAutomationPeer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ protected override int GetPositionInSetCore()
103103

104104
private IList GetOwnerCollection()
105105
{
106-
if (Owner.FindAscendant<SidebarItem>() is SidebarItem parent && parent.Children is IList list)
106+
if (Owner.FindAscendant<SidebarItem>() is SidebarItem parent && parent.Item?.Children is IList list)
107107
return list;
108108

109109
if (Owner?.Owner is not null && Owner.Owner?.MenuItemsSource is IList items)

src/Files.App.Controls/Sidebar/SidebarStyles.xaml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,9 @@
3939
<DataTemplate x:Key="DefaultSidebarItemTemplate">
4040
<local:SidebarItem
4141
AutomationProperties.AutomationId="{Binding Text}"
42-
Children="{Binding Children}"
4342
Decorator="{Binding ItemDecorator}"
4443
Icon="{Binding IconElement}"
4544
IsExpanded="{Binding IsExpanded, Mode=TwoWay}"
46-
IsPaddedItem="{Binding PaddedItem}"
4745
Item="{Binding}"
4846
Text="{Binding Text}"
4947
ToolTip="{Binding ToolTip}" />
@@ -195,10 +193,24 @@
195193
<ItemsRepeater
196194
x:Name="FlyoutChildrenPresenter"
197195
HorizontalAlignment="Stretch"
196+
local:SidebarItem.TemplateRoot="{Binding ElementName=RootPanel}"
198197
AutomationProperties.AccessibilityView="Content"
199-
ItemTemplate="{StaticResource DefaultSidebarItemTemplate}"
200-
ItemsSource="{TemplateBinding Children}"
201-
XYFocusKeyboardNavigation="Enabled" />
198+
ItemsSource="{Binding Children, Mode=OneWay}"
199+
XYFocusKeyboardNavigation="Enabled">
200+
<ItemsRepeater.ItemTemplate>
201+
<DataTemplate>
202+
<local:SidebarItem
203+
AutomationProperties.AutomationId="{Binding Text}"
204+
Decorator="{Binding ItemDecorator}"
205+
Icon="{Binding IconElement}"
206+
IsExpanded="{Binding IsExpanded, Mode=TwoWay}"
207+
IsInFlyout="True"
208+
Item="{Binding}"
209+
Text="{Binding Text}"
210+
ToolTip="{Binding ToolTip}" />
211+
</DataTemplate>
212+
</ItemsRepeater.ItemTemplate>
213+
</ItemsRepeater>
202214
</Flyout>
203215
</FlyoutBase.AttachedFlyout>
204216
</Grid>
@@ -210,9 +222,10 @@
210222
Grid.Row="2"
211223
Margin="-4,2"
212224
HorizontalAlignment="Stretch"
225+
local:SidebarItem.TemplateRoot="{Binding ElementName=RootPanel}"
213226
AutomationProperties.AccessibilityView="Content"
214227
ItemTemplate="{StaticResource DefaultSidebarItemTemplate}"
215-
ItemsSource="{TemplateBinding Children}"
228+
ItemsSource="{Binding Children, Mode=OneWay}"
216229
Visibility="Collapsed"
217230
XYFocusKeyboardNavigation="Enabled">
218231
<ItemsRepeater.Layout>

src/Files.App.Controls/Sidebar/SidebarView.Properties.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) Files Community
22
// Licensed under the MIT License.
33

4-
using CommunityToolkit.WinUI;
5-
64
namespace Files.App.Controls
75
{
86
public sealed partial class SidebarView
@@ -67,13 +65,16 @@ public double NegativeOpenPaneLength
6765
public static readonly DependencyProperty NegativeOpenPaneLengthProperty =
6866
DependencyProperty.Register(nameof(NegativeOpenPaneLength), typeof(double), typeof(SidebarView), new PropertyMetadata(null));
6967

70-
public object SelectedItem
68+
public ISidebarItemModel SelectedItem
7169
{
72-
get => GetValue(SelectedItemProperty);
73-
set => SetValue(SelectedItemProperty, value);
70+
get => (ISidebarItemModel)GetValue(SelectedItemProperty);
71+
set
72+
{
73+
SetValue(SelectedItemProperty, value);
74+
}
7475
}
7576
public static readonly DependencyProperty SelectedItemProperty =
76-
DependencyProperty.Register(nameof(SelectedItem), typeof(object), typeof(SidebarView), new PropertyMetadata(null));
77+
DependencyProperty.Register(nameof(SelectedItem), typeof(ISidebarItemModel), typeof(SidebarView), new PropertyMetadata(null));
7778

7879
public object MenuItemsSource
7980
{

0 commit comments

Comments
 (0)