wpfui icon indicating copy to clipboard operation
wpfui copied to clipboard

Cannot add Navigation view items during Runtime

Open misakieku opened this issue 2 years ago • 12 comments

Describe the bug

I am trying to add new Items based on configuration after the user open the app but the issue is I cannot see that the item is been added to the navigation view. The code I have now:

            var item = AppDataUtilities.AddAppItem(appData);
            navigationView.MenuItems.Add(item);
            navigationView.UpdateLayout();

To Reproduce

Add NavigationViewItem during runtime, like event.

Expected behavior

NavigationView able to react the changes.

Screenshots

No response

OS version

Windows 11 VS 2022

.NET version

.Net 8

WPF-UI NuGet version

3.0.0 preview4

Additional context

No response

misakieku avatar Jan 08 '24 22:01 misakieku

In Wpf.Ui.Controls.NavigationView source code, there is an update menu items template function. You can manually update it by doing the same for loop after adding your items in your code. just copy the for loop and adjust according to your variables. This is how i solved it at least.

protected virtual void UpdateMenuItemsTemplate(IList list) { for (int i = 0; i < list.Count; i++) { if (list[i] is NavigationViewItem navigationViewItem && ItemTemplate != null && navigationViewItem.Template != ItemTemplate) { navigationViewItem.Template = ItemTemplate; } } }

EkinBarisC avatar Jan 10 '24 15:01 EkinBarisC

In Wpf.Ui.Controls.NavigationView source code, there is an update menu items template function. You can manually update it by doing the same for loop after adding your items in your code. just copy the for loop and adjust according to your variables. This is how i solved it at least.

protected virtual void UpdateMenuItemsTemplate(IList list) { for (int i = 0; i < list.Count; i++) { if (list[i] is NavigationViewItem navigationViewItem && ItemTemplate != null && navigationViewItem.Template != ItemTemplate) { navigationViewItem.Template = ItemTemplate; } } }

It did work. However, OnNavigationSelectionChanged will not be trigger if I select the new item that I added.

misakieku avatar Jan 11 '24 15:01 misakieku

And this seams not working if I add the item as a subitem of another navigation view item.

misakieku avatar Jan 12 '24 12:01 misakieku

You are right. I made a workaround by recreating the navigation view at every update and then re initialize it in the xaml. I also add the selection changed events which triggers it successfully. This works for me but it is not a good way of updating it at all.

` var newNavigationView = new NavigationView { MenuItemsSource = MenuItems, Header = NavigationView.Header, IsPaneOpen = NavigationView.IsPaneOpen, PaneDisplayMode = NavigationView.PaneDisplayMode, };

newNavigationView.SelectionChanged += NavigationView_SelectionChanged; var parent = NavigationView.Parent as Panel; if (parent != null) { int index = parent.Children.IndexOf(NavigationView); parent.Children.RemoveAt(index); parent.Children.Insert(index, newNavigationView); }

NavigationService.SetNavigationControl(newNavigationView);

NavigationView = newNavigationView;`

EkinBarisC avatar Jan 12 '24 12:01 EkinBarisC

You are right. I made a workaround by recreating the navigation view at every update and then re initialize it in the xaml. I also add the selection changed events which triggers it successfully. This works for me but it is not a good way of updating it at all.

` var newNavigationView = new NavigationView { MenuItemsSource = MenuItems, Header = NavigationView.Header, IsPaneOpen = NavigationView.IsPaneOpen, PaneDisplayMode = NavigationView.PaneDisplayMode, };

newNavigationView.SelectionChanged += NavigationView_SelectionChanged; var parent = NavigationView.Parent as Panel; if (parent != null) { int index = parent.Children.IndexOf(NavigationView); parent.Children.RemoveAt(index); parent.Children.Insert(index, newNavigationView); }

NavigationService.SetNavigationControl(newNavigationView);

NavigationView = newNavigationView;`

Thanks a lot.

misakieku avatar Jan 15 '24 05:01 misakieku

after some research I found the following solution

I change the Visible value instead of adding and removing the menu item


      <ui:NavigationView x:Name="NavigationView" Grid.Row="1" Padding="10,0,10,0"
              BreadcrumbBar="{Binding ElementName=BreadcrumbBar}"
              FooterMenuItemsSource="{Binding ViewModel.FooterMenuItems, Mode=OneWay}" FrameMargin="0"
              IsBackButtonVisible="Visible" IsPaneToggleVisible="True" PaneDisplayMode="LeftFluent">
          <ui:NavigationView.Header>
              <ui:BreadcrumbBar x:Name="BreadcrumbBar" Margin="10,5,10,5" />
          </ui:NavigationView.Header>
          <ui:NavigationView.ContentOverlay>
              <Grid>
                  <ui:SnackbarPresenter x:Name="SnackbarPresenter" />
              </Grid>
          </ui:NavigationView.ContentOverlay>

          <ui:NavigationView.MenuItems>
              <ui:NavigationViewItem Content="Devices" TargetPageType="{x:Type pages:DevicesPage}">
                  <ui:NavigationViewItem.Icon>
                      <ui:SymbolIcon Symbol="DeviceEq20" />
                  </ui:NavigationViewItem.Icon>
              </ui:NavigationViewItem>

              <ui:NavigationViewItem Content="Users" TargetPageType="{x:Type pages:UsersPage}">
                  <ui:NavigationViewItem.Icon>
                      <ui:SymbolIcon Symbol="People20" />
                  </ui:NavigationViewItem.Icon>
              </ui:NavigationViewItem>


              <ui:NavigationViewItem Content="Account" TargetPageType="{x:Type pages:AccountPage}">
                  <ui:NavigationViewItem.Icon>
                      <ui:SymbolIcon Symbol="NotepadPerson20" />
                  </ui:NavigationViewItem.Icon>
              </ui:NavigationViewItem>
              <!--look here trick is here-->
              <ui:NavigationViewItem Content="Connected" TargetPageType="{x:Type pages:SettingsPage}"
                                     
                                     Visibility="{Binding ViewModel.ShowConnectedTab, Converter={StaticResource BoolToVisibleConvertor}}"
                                     >
                  <ui:NavigationViewItem.Icon>
                      <ui:SymbolIcon Symbol="NotepadPerson20" />
                  </ui:NavigationViewItem.Icon>
              </ui:NavigationViewItem>

          </ui:NavigationView.MenuItems>


      </ui:NavigationView>

And my view model

  public partial class MainWindowViewModel : ObservableObject {

       [ObservableProperty]
       private string _applicationTitle = "Modibus Client";

       [ObservableProperty]
       private bool _showConnectedTab = false;

       [ObservableProperty]
       private ObservableCollection<object> _footerMenuItems = new()
       {
           new NavigationViewItem()
           {
               Content = "Settings",
               Icon = new SymbolIcon { Symbol = SymbolRegular.Settings20 },
               TargetPageType = typeof(Views.Pages.SettingsPage)
           },
             new NavigationViewItem()
           {
               Content = "Logout",
               Icon = new SymbolIcon { Symbol = SymbolRegular.ArrowExit20 },
               TargetPageType = typeof(Views.Pages.SettingsPage)
           },

       };



       [ObservableProperty]
       public string _deviceName = "device name";

       [ObservableProperty]
       public string _location = "location";

       // LOOK
       [RelayCommand]
       public void OnShowConnectedTab() {
           ShowConnectedTab = true;
       }    
       [RelayCommand]
       public void OnHideConnectedTab() {
           ShowConnectedTab = false;
       }

   }

and my converter class

internal class BoolToVisibleConvertor : IValueConverter {
    public object Convert(object value,Type targetType,object parameter,CultureInfo culture) {
       return (bool)value  ? Visibility.Visible : Visibility.Hidden;
    }

    public object ConvertBack(object value,Type targetType,object parameter,CultureInfo culture) {
        throw new NotImplementedException();
    }
}

sbaskoy avatar Jan 31 '24 14:01 sbaskoy

hi, Wpf.Ui.Controls.NavigationView source code NavigationView.Navigation.cs line: 175 - 213 - 219

 if (SelectedItem != NavigationStack[0] && NavigationStack[0].IsMenuElement)
 {
     SelectedItem = NavigationStack[0];
     OnSelectionChanged();
 }

if your item is NavigationViewItem , try :
var item = AppDataUtilities.AddAppItem(appData); item.Template = navigationView.ItemTemplate; item.IsMenuElement = true; navigationView.MenuItems.Add(item);

good luck!

scanfing avatar Feb 20 '24 03:02 scanfing

I also have the same problem, but I hope to change the item by changing the item of ObservableCollection

public partial class MainWindow : IWindow
{
    public MainWindowViewModel ViewModel
    {
        get;
    }
    public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvider, INavigationService navigationService)
    {

        ViewModel = viewModel;
        // ViewModel.MenuItems = ViewModel.GetMenuItemsByAuth();//with navigation
        this.DataContext = this;

        viewModel.ApplicationTitle = "111111111";

        InitializeComponent();

        this.Loaded += MainWindow_Loaded;

        navigationService.SetNavigationControl(NavigationView);

        NavigationView.SetServiceProvider(serviceProvider);
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        //ViewModel.MenuItems=  ViewModel.GetMenuItemsByAuth();//no Navigation
       // NavigationView.MenuItems = ViewModel.GetMenuItemsByAuth();// no Navigation
       // ViewModel.MenuItems.Add(new NavigationViewItem("11", SymbolRegular.Grid20, typeof(TestPage)));// no Navigation
        NavigationView.MenuItems.Add(new NavigationViewItem("11", SymbolRegular.Grid20, typeof(TestPage)));// no Navigation
    }

zhouxinmail avatar Feb 29 '24 03:02 zhouxinmail

hi, Wpf.Ui.Controls.NavigationView source code NavigationView.Navigation.cs line: 175 - 213 - 219

 if (SelectedItem != NavigationStack[0] && NavigationStack[0].IsMenuElement)
 {
     SelectedItem = NavigationStack[0];
     OnSelectionChanged();
 }

if your item is NavigationViewItem , try : var item = AppDataUtilities.AddAppItem(appData); item.Template = navigationView.ItemTemplate; item.IsMenuElement = true; navigationView.MenuItems.Add(item);

good luck!

Thanks, I also encountered this problem. Thank you for your answer

happygb21-jc avatar Feb 29 '24 03:02 happygb21-jc

我也有同样的问题,但我希望通过更改ObservableCollection的项目来更改项目

public partial class MainWindow : IWindow
{
    public MainWindowViewModel ViewModel
    {
        get;
    }
    public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvider, INavigationService navigationService)
    {

        ViewModel = viewModel;
        // ViewModel.MenuItems = ViewModel.GetMenuItemsByAuth();//with navigation
        this.DataContext = this;

        viewModel.ApplicationTitle = "111111111";

        InitializeComponent();

        this.Loaded += MainWindow_Loaded;

        navigationService.SetNavigationControl(NavigationView);

        NavigationView.SetServiceProvider(serviceProvider);
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        //ViewModel.MenuItems=  ViewModel.GetMenuItemsByAuth();//no Navigation
       // NavigationView.MenuItems = ViewModel.GetMenuItemsByAuth();// no Navigation
       // ViewModel.MenuItems.Add(new NavigationViewItem("11", SymbolRegular.Grid20, typeof(TestPage)));// no Navigation
        NavigationView.MenuItems.Add(new NavigationViewItem("11", SymbolRegular.Grid20, typeof(TestPage)));// no Navigation
    }

You can obtain the itemTemplate in navigationService navigationViewItem.Template = navigationService.GetNavigationControl().ItemTemplate; You can try it

happygb21-jc avatar Feb 29 '24 03:02 happygb21-jc

But the indentation of the submenu is incorrect

zhouxinmail avatar Feb 29 '24 03:02 zhouxinmail

But the indentation of the submenu is incorrect

base on: https://github.com/lepoco/wpfui/pull/964/files

image

image

You can refer to the above content about ObservableCollection.

scanfing avatar Feb 29 '24 08:02 scanfing