55using Microsoft . UI . Input ;
66using Microsoft . UI . Xaml . Automation ;
77using Microsoft . UI . Xaml . Automation . Peers ;
8- using Microsoft . UI . Xaml . Media ;
98using System . Collections . Specialized ;
109using 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 ;
0 commit comments