@@ -4104,12 +4104,13 @@ private void ReconcileTreeNodeContent(
41044104 /// </summary>
41054105 private UIElement ? UpdateTemplatedTreeView ( TemplatedTreeViewElementBase o , TemplatedTreeViewElementBase n , WinUI . TreeView tv , Action requestRerender )
41064106 {
4107- // The internal list (if realized) lets us reconcile the views of
4108- // currently-realized containers. Unrealized nodes need no work — their
4109- // view is (re)built fresh from node.Content when they next realize.
4110- var list = FindTypedTreeListControl ( tv ) ;
4111-
4112- DiffTemplatedTreeNodes ( tv . RootNodes , list , o , o . GetRoots ( ) , n , n . GetRoots ( ) , requestRerender ) ;
4107+ // Diff the node hierarchy (structure + each node's data item). The view
4108+ // reconcile is a separate flat pass over the realized containers below —
4109+ // keeping the two concerns decoupled, and using the index-based container
4110+ // lookup that works under NativeAOT (ContainerFromItem does not resolve
4111+ // there, and a freshly-realized container can still be the base
4112+ // ListViewItem rather than TreeViewItem).
4113+ DiffTemplatedTreeNodes ( tv . RootNodes , o , o . GetRoots ( ) , n , n . GetRoots ( ) ) ;
41134114
41144115 tv . SelectionMode = n . GetSelectionMode ( ) ;
41154116 tv . CanDragItems = n . GetCanDragItems ( ) ;
@@ -4118,9 +4119,45 @@ private void ReconcileTreeNodeContent(
41184119
41194120 SetElementTag ( tv , n ) ;
41204121 n . ApplyControlSetters ( tv ) ;
4122+
4123+ // Reconcile the view of every currently-realized container against its
4124+ // node's (now-updated) data. Unrealized nodes need no work — their view
4125+ // is (re)built fresh from node.Content when they next realize via CCC.
4126+ RefreshRealizedTreeContainers ( tv , FindTypedTreeListControl ( tv ) , n , requestRerender ) ;
41214127 return null ;
41224128 }
41234129
4130+ /// <summary>
4131+ /// Reconciles the hosted view of every realized container against its node's
4132+ /// current <c>node.Content</c> data. Iterates the flattened
4133+ /// <see cref="WinUI.ListView.Items"/> via index (the AOT-robust lookup), so
4134+ /// it covers visible nodes at every depth in one pass.
4135+ /// </summary>
4136+ private void RefreshRealizedTreeContainers ( WinUI . TreeView tv , WinUI . ListView ? list , TemplatedTreeViewElementBase n , Action requestRerender )
4137+ {
4138+ if ( list is null ) return ;
4139+ for ( int i = 0 ; i < list . Items . Count ; i ++ )
4140+ {
4141+ if ( list . ContainerFromIndex ( i ) is not ContentControl container ) continue ;
4142+ if ( container . ContentTemplateRoot is not ContentControl cc ) continue ;
4143+ if ( list . Items [ i ] is not WinUI . TreeViewNode node || node . Content is not { } data ) continue ;
4144+
4145+ var newView = n . BuildView ( data ) ;
4146+ if ( cc . Content is UIElement existing && GetElementTag ( cc ) is Element oldView && CanUpdate ( oldView , newView ) )
4147+ {
4148+ var replacement = Update ( oldView , newView , existing , requestRerender ) ;
4149+ if ( replacement is not null && ! ReferenceEquals ( cc . Content , replacement ) )
4150+ cc . Content = replacement ;
4151+ }
4152+ else
4153+ {
4154+ if ( cc . Content is UIElement old ) UnmountChild ( old ) ;
4155+ cc . Content = Mount ( newView , requestRerender ) ;
4156+ }
4157+ SetElementTag ( cc , newView ) ;
4158+ }
4159+ }
4160+
41244161 private static readonly object [ ] s_emptyTreeItems = [ ] ;
41254162
41264163 /// <summary>
@@ -4134,10 +4171,8 @@ private void ReconcileTreeNodeContent(
41344171 /// </summary>
41354172 private void DiffTemplatedTreeNodes (
41364173 IList < WinUI . TreeViewNode > liveNodes ,
4137- WinUI . ListView ? list ,
41384174 TemplatedTreeViewElementBase oldEl , IReadOnlyList < object > oldItems ,
4139- TemplatedTreeViewElementBase newEl , IReadOnlyList < object > newItems ,
4140- Action requestRerender )
4175+ TemplatedTreeViewElementBase newEl , IReadOnlyList < object > newItems )
41414176 {
41424177 // Snapshot: map old key → (live node, old item). Live nodes correspond
41434178 // 1:1 to oldItems in order.
@@ -4161,13 +4196,10 @@ private void DiffTemplatedTreeNodes(
41614196 bool expanded = newEl . GetIsExpanded ( newItem ) ;
41624197 if ( node . IsExpanded != expanded ) node . IsExpanded = expanded ;
41634198
4164- ReconcileRealizedTreeContainer ( list , node , newEl , newItem , requestRerender ) ;
4165-
41664199 DiffTemplatedTreeNodes (
4167- node . Children , list ,
4200+ node . Children ,
41684201 oldEl , oldEl . GetChildren ( match . OldItem ) ?? s_emptyTreeItems ,
4169- newEl , newEl . GetChildren ( newItem ) ?? s_emptyTreeItems ,
4170- requestRerender ) ;
4202+ newEl , newEl . GetChildren ( newItem ) ?? s_emptyTreeItems ) ;
41714203
41724204 target . Add ( node ) ;
41734205 }
@@ -4206,33 +4238,6 @@ private static int IndexOfNode(IList<WinUI.TreeViewNode> nodes, WinUI.TreeViewNo
42064238 return - 1 ;
42074239 }
42084240
4209- /// <summary>
4210- /// Reconciles the view hosted in a matched node's realized container (if it
4211- /// is currently realized). Updates in place when the old/new views are
4212- /// compatible, otherwise unmounts and re-mounts. Unrealized nodes are
4213- /// skipped — they rebuild fresh from <c>node.Content</c> on next realization.
4214- /// </summary>
4215- private void ReconcileRealizedTreeContainer (
4216- WinUI . ListView ? list , WinUI . TreeViewNode node , TemplatedTreeViewElementBase newEl , object newItem , Action requestRerender )
4217- {
4218- if ( list ? . ContainerFromItem ( node ) is not WinUI . TreeViewItem container ) return ;
4219- if ( container . ContentTemplateRoot is not ContentControl cc ) return ;
4220-
4221- var newView = newEl . BuildView ( newItem ) ;
4222- if ( cc . Content is UIElement existing && GetElementTag ( cc ) is Element oldView && CanUpdate ( oldView , newView ) )
4223- {
4224- var replacement = Update ( oldView , newView , existing , requestRerender ) ;
4225- if ( replacement is not null && ! ReferenceEquals ( cc . Content , replacement ) )
4226- cc . Content = replacement ;
4227- }
4228- else
4229- {
4230- if ( cc . Content is UIElement old ) UnmountChild ( old ) ;
4231- cc . Content = Mount ( newView , requestRerender ) ;
4232- }
4233- SetElementTag ( cc , newView ) ;
4234- }
4235-
42364241 private UIElement ? UpdateRectangle ( RectangleElement n , WinShapes . Rectangle r )
42374242 {
42384243 if ( n . Fill is not null ) r . Fill = n . Fill ;
0 commit comments