@@ -117,6 +117,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
117
117
lastBreadcrumb = _breadcrumbs.GetAt (size - 1 );
118
118
}
119
119
120
+ // Collect all the values out of the old nav view item source
120
121
auto menuItems{ SettingsNav ().MenuItems () };
121
122
122
123
// We'll remove a bunch of items and iterate over it twice.
@@ -156,7 +157,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
156
157
}),
157
158
menuItemsSTL.end ());
158
159
159
- menuItems.ReplaceAll (menuItemsSTL);
160
+ // Now, we've got a list of just the static entries again. Lets take
161
+ // those and stick them back into a new winrt vector, and set that as
162
+ // the source again.
163
+ //
164
+ // By setting MenuItemsSource in its entirety, rather than manipulating
165
+ // MenuItems, we avoid a crash in WinUI.
166
+ auto newSource = winrt::single_threaded_vector<IInspectable>(std::move (menuItemsSTL));
167
+ SettingsNav ().MenuItemsSource (newSource);
160
168
161
169
// Repopulate profile-related menu items
162
170
_InitializeProfilesList ();
@@ -209,7 +217,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
209
217
// Couldn't find the selected item, fallback to first menu item
210
218
// This happens when the selected item was a profile which doesn't exist in the new configuration
211
219
// We can use menuItemsSTL here because the only things they miss are profile entries.
212
- const auto & firstItem{ menuItemsSTL. at (0 ).as <MUX::Controls::NavigationViewItem>() };
220
+ const auto & firstItem{ SettingsNav (). MenuItems (). GetAt (0 ).as <MUX::Controls::NavigationViewItem>() };
213
221
SettingsNav ().SelectedItem (firstItem);
214
222
_Navigate (unbox_value<hstring>(firstItem.Tag ()), BreadcrumbSubPage::None);
215
223
}
@@ -527,7 +535,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
527
535
528
536
void MainPage::_InitializeProfilesList ()
529
537
{
530
- const auto menuItems = SettingsNav ().MenuItems ();
538
+ const auto & itemSource{ SettingsNav ().MenuItemsSource () };
539
+ if (!itemSource)
540
+ {
541
+ // There wasn't a MenuItemsSource set yet? The only way that's
542
+ // possible is if we haven't used
543
+ // _MoveXamlParsedNavItemsIntoItemSource to move the hardcoded menu
544
+ // entries from XAML into our runtime menu item source. Do that now.
545
+
546
+ _MoveXamlParsedNavItemsIntoItemSource ();
547
+ }
548
+ const auto menuItems = SettingsNav ().MenuItemsSource ().try_as <IVector<IInspectable>>();
531
549
532
550
// Manually create a NavigationViewItem for each profile
533
551
// and keep a reference to them in a map so that we
@@ -557,6 +575,37 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
557
575
menuItems.Append (addProfileItem);
558
576
}
559
577
578
+ // BODGY
579
+ // Does the very wacky business of moving all our MenuItems that we
580
+ // hardcoded in XAML into a runtime MenuItemsSource. We'll then use _that_
581
+ // MenuItemsSource as the source for our nav view entries instead. This
582
+ // lets us hardcode the initial entries in precompiled XAML, but then adjust
583
+ // the items at runtime. Without using a MenuItemsSource, the NavView just
584
+ // crashes when items are removed (see GH#13673)
585
+ void MainPage::_MoveXamlParsedNavItemsIntoItemSource ()
586
+ {
587
+ if (SettingsNav ().MenuItemsSource ())
588
+ {
589
+ // We've already copied over the original items to a source. We can
590
+ // just skip this now.
591
+ return ;
592
+ }
593
+
594
+ auto menuItems{ SettingsNav ().MenuItems () };
595
+ // Remove all the existing items, and move them to a separate vector
596
+ // that we'll use as a MenuItemsSource. By doing this, we avoid a WinUI
597
+ // bug (MUX#6302) where modifying the NavView.Items() directly causes a
598
+ // crash. By leaving these static entries in XAML, we maintain the
599
+ // benefit of instantiating them from the XBF, rather than at runtime.
600
+ //
601
+ // --> Copy it into an STL vector to simplify our code and reduce COM overhead.
602
+ std::vector<IInspectable> menuItemsSTL (menuItems.Size (), nullptr );
603
+ menuItems.GetMany (0 , menuItemsSTL);
604
+
605
+ auto newSource = winrt::single_threaded_vector<IInspectable>(std::move (menuItemsSTL));
606
+ SettingsNav ().MenuItemsSource (newSource);
607
+ }
608
+
560
609
void MainPage::_CreateAndNavigateToNewProfile (const uint32_t index, const Model::Profile& profile)
561
610
{
562
611
const auto newProfile{ profile ? profile : _settingsClone.CreateNewProfile () };
0 commit comments