Reputation: 270
I'm creating a simple desktop app. The app will have three items in the flyout, and the flyout is locked. The first item in the flyout will route to it's own page. However, the second two pages will essentially be the same (same content page/view model), but dynamic information needs to get passed to it. I'm able to do this with a query property, but the app does not always load the correct page when I select flyout items.
Specifically, the behavior is as follows:
I'm using the CommunityToolkit.Mvvm nuget package.
From my AppShell.xaml:
<FlyoutItem Title="Unique">
<Tab>
<ShellContent
ContentTemplate="{DataTemplate local:MVVM.View.UniquePage}"
Route="UniquePage" />
</Tab>
</FlyoutItem>
<FlyoutItem Title="Variant 1">
<Tab>
<ShellContent
ContentTemplate="{DataTemplate local:MVVM.View.VariantPage}"
Route="VariantPage?Side=Test1" />
</Tab>
</FlyoutItem>
<FlyoutItem Title="Variant 2">
<Tab>
<ShellContent
ContentTemplate="{DataTemplate local:MVVM.View.VariantPage}"
Route="VariantPage?Side=Test2" />
</Tab>
</FlyoutItem>
In the backing .cs file for AppShell.xaml I'm registering the route to each page using nameof()
and typeof()
.
ViewModel for VariantPage:
[QueryProperty(nameof(Side), nameof(Side))]
public partial class VariantViewModel : BaseViewModel
{
public ObservableCollection<Widget> Widgets{ get; } = new();
ConfigurationService configService;
[ObservableProperty]
private string side = "Left";
public VariantViewModel(ConfigurationService service)
{
this.configService = service;
LoadWidgets();
}
private void LoadWidgets()
{
//assigns stuff to Widgets
}
}
BaseViewModel inherits from ObservableObject. Backing for VariantPage looks like this:
public VariantPage(VariantViewModel viewModel)
{
BindingContext = viewModel;
InitializeComponent();
}
protected override void OnNavigatedTo(NavigatedToEventArgs args)
{
base.OnNavigatedTo(args);
}
Finally, MauiProgram.cs builder is registering the following:
builder.Services.AddSingleton<ConfigurationService>();
builder.Services.AddSingleton<VariantViewModel>();
builder.Services.AddSingleton<VariantPage>();
builder.Services.AddSingleton<UniqueViewModel>();
builder.Services.AddSingleton<UniquePage>();
Any suggestions or explanation on how to get consistent behavior would be much appreciated.
Upvotes: 0
Views: 2448
Reputation: 8220
Here is a workaround for you. Override the OnNavigation method and use MessagingCenter to change the value of Side. You could try the following code:
In AppShell.cs, publish a message each time when navigating:
protected override void OnNavigating(ShellNavigatingEventArgs args)
{
base.OnNavigating(args);
if (args.Target.Location.OriginalString.Contains("VariantPage1"))
{
MessagingCenter.Send<AppShell, string>(this, "Hi", "Test1");
}
if (args.Target.Location.OriginalString.Contains("VariantPage2"))
{
MessagingCenter.Send<AppShell, string>(this, "Hi", "Test2");
}
}
Routes can be defined on FlyoutItem, TabBar, Tab, and ShellContent objects, through their Route properties. So you don't have to register in AppShell.cs any more.
<FlyoutItem Title="Variant 1">
<Tab>
<ShellContent
ContentTemplate="{DataTemplate local:VariantPage}"
Route="VariantPage1">
</ShellContent>
</Tab>
</FlyoutItem>
<FlyoutItem Title="Variant 2">
<Tab>
<ShellContent
ContentTemplate="{DataTemplate local:VariantPage}"
Route="VariantPage2" />
</Tab>
</FlyoutItem>
And for VariantViewModel, subscribe to the message
[ObservableProperty]
private string side = "Left";
public VariantViewModel(ConfigurationService service)
{
this.configService = service;
LoadWidgets();
MessagingCenter.Subscribe<AppShell, string>(this, "Hi", (sender, arg) =>
{
Side = arg;
});
}
For more info, you could refer to Publish and subscribe to messages
Hope it works.
Upvotes: 1
Reputation: 3907
I do not know where to start.
This "Singleton" both for ViewModel and View. The attempt to pass parameters in shell XAML. The Widgets loading in constructor.
I will give you the workarounds you ask, but you are walking towards much bigger problems.
First: You can override OnNavigating. (This is in your shell code) Check your event.Target.Location. Set the data you want to your ViewModel, depending where you navigate to.
Second: You can override OnNavigatedTo. (This is in your Page, but can be passed on to the ViewModel as command) Check your Shell.Current.CurrentState.Location. Set the data you want.
You can check this every now and then: https://github.com/dotnet/maui/issues/3868
Upvotes: 1