FluentAvalonia
FluentAvalonia copied to clipboard
NavigationView.SelectedItem is not updating its selection state when setting the selected item from ViewModel
Hello everybody,
I've bound the NavigationView.SelectedItem to my VMs property 'SelectedModuleMenuItem'. When i change the SelectedModuleMenuItem in my VMs code, the selection in NavigationView is not updated.
Screenshots
Desktop (please complete the following information):
- OS: Windows 10
- FluentAvalonia Version 1.2.1
- Avalonia Version 0.10.12
Thx for your help!
I'm unable to repro this behavior. Do you have some sample code or a minimal repro? Are you trying to use the Menu to select the NavigationView items? If so, that may be the problem, because of the way menus are implemented.
Hi,
yes, u r right - i'm using a Menu to select the current NavigationViewItem. The XAML of the Menu looks like this.
<Menu Margin="0,0,0,10" DockPanel.Dock="Top" Items="{Binding MenuItems}">
<Menu.Styles>
<Style Selector="MenuItem">
<Setter Property="ClipToBounds" Value="false" />
<Setter Property="Header" Value="{Binding Text}"/>
<Setter Property="Items" Value="{Binding Items}"/>
<Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>
</Style>
</Menu.Styles>
</Menu>
And the NavigationMenu XAML like this:
<ui:NavigationView PaneTitle="Hauptmenu" MenuItems="{Binding ModuleMenuItems}" SelectedItem="{Binding SelectedModuleMenuItem}">
<ui:NavigationView.MenuItemTemplate>
<DataTemplate>
<ui:NavigationViewItem Content="{Binding Text}" Icon="{Binding Icon}" ToolTip.Tip="{Binding ToolTip}" MenuItems="{Binding Items}" />
</DataTemplate>
</ui:NavigationView.MenuItemTemplate>
</ui:NavigationView>
In my ViewModel the MenuItems are created as following:
ModuleMenuItems = new[] {
new ModuleMenuItemViewModel { Text = "Stammdaten", Items = new[] {
new ModuleMenuItemViewModel { Text = "Produkte", Heading="Produkte", ModuleViewModel = new ProductsViewModel(), Command = ShowModuleCommand },
new ModuleMenuItemViewModel { Text = "Adressen", Heading ="Adressen", ModuleViewModel = new AddressViewModel(), Command = ShowModuleCommand },
}
}
The Bound Command of the MenuItems set the SelectedModuleMenuItem
which is also bound to the NavigationView SelectedItem
:
private void DoShowModule(ModuleMenuItemViewModel mmivm)
{
SelectedModuleMenuItem = mmivm;
}
ModuleMenuItemViewModel _SelectedModuleMenuItem;
public ModuleMenuItemViewModel SelectedModuleMenuItem
{
get => _SelectedModuleMenuItem;
set
{
if (value != null && value.ModuleViewModel != null
&& (CurrentModuleViewModel == null || CurrentModuleViewModel.CanDeactivateViewModel()))
{
this.RaiseAndSetIfChanged(ref _SelectedModuleMenuItem, value);
CurrentModuleViewModel = value.ModuleViewModel;
}
}
}
For the sake of completness here also the ModuleMenuItemViewModel
class
public class ModuleMenuItemViewModel : MenuItemViewModel
{
string _Heading;
public string Heading { get => _Heading; internal set => this.RaiseAndSetIfChanged(ref _Heading, value); }
ModuleViewModelBase _ModuleViewModel;
public ModuleViewModelBase ModuleViewModel { get => _ModuleViewModel; internal set => this.RaiseAndSetIfChanged(ref _ModuleViewModel, value); }
}
BR, hematec
Still unable to repro this. The code fragments were still missing some components so I had to try to piece together what you were doing - however I'm still able to successfully bind a command to a MenuItem that programmatically sets the SelectedItem in the VM and get the selection to properly update in the NavigationView.
A couple of notes... 1 - Is there a reason you need both the MenuBar and the NavigationView? They're both considered top-level navigation controls and probably don't need to be used together since they accomplish the same thing.
2 - It looks like you're using the old Fluent theme from upstream in Avalonia in conjunction with the NavigationView - which doesn't natively support the old theme since v1.1.5? when I removed support for it. It's possible there's some funny business going on there with the styles that's making this happen?
I have made an example here where the problem is visible. I am not using the NavigationView quite as intended, as I want to instantiate my own view models and use Reactive UI.
This is a somewhat related question. I want my view models to have constructor parameters like services. Is it possible to set the data context of the page to navigate to when using the frame control? Or is it possible that they get injected by the framework (but since System.Activator is used, I doubt it)? Is it the best practice to use optional constructor parameters, that fall back to a static reference if it is not passed through the constructor, allowing unit tests, but still has default constructors when used by Avalonia?
I made an even simpler example here: https://github.com/taj-ny/FATest.
Pressing the "Navigate to page 2" button would result in a "Call from invalid thread" exception. However, I forgot to add UseReactiveUI()
to BuildAvaloniaApp
. So I added it and got the same issue.
This problem seems to be somehow caused by ReactiveCommand
. I replaced it with CommunityToolkit.Mvvm's RelayCommand, which is what I use in my projects, and everything works correctly.
public MainWindowViewModel()
{
- NavigateToPage2Command = new ReactiveCommand.Create(NavigateToPage2);
+ NavigateToPage2Command = new RelayCommand(NavigateToPage2);
}
This fix also works for Laurnz's example.