Reputation: 164
There is a template for displaying data with a ViewModel.
BaseTabView.xaml
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Oss.Maui.Views.Tabs.BaseTabView"
xmlns:vm="clr-namespace:Oss.ViewModels.Tabs;assembly=Oss.ViewModels"
xmlns:controls="clr-namespace:Oss.Maui.Controls;assembly=Oss.Maui.Controls"
x:DataType="vm:BaseTabViewModel">
<ContentPage.Content>
<controls:HybridWebView x:Name="HybridView" Url="{Binding Url}" Source="{Binding Url}" LocalStoragesValue="{Binding LocalStorage}" />
</ContentPage.Content>
</ContentPage>
BaseTabView.xaml.cs
public partial class BaseTabView : ContentPage
{
public BaseTabView()
{
InitializeComponent();
#if ANDROID
HybridView.JsBridge = ServiceLocator.GetService<IJsBridge<IOssAction>>();
#endif
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
}
}
Basic ViewModel for displaying
public class BaseTabViewModel : ViewModel
{
protected readonly IMauiApplicationViewModel MauiApplicationViewModel;
public BaseTabViewModel(IApplication application, IMauiApplicationViewModel mauiApplicationViewModel)
: base(application)
{
MauiApplicationViewModel = mauiApplicationViewModel;
LocalStorage = new Dictionary<string, string>()
{
{"oss.locale", $"\"{mauiApplicationViewModel.PersonalSettings.CurrentCulture.TwoLetterISOLanguageName}\""},
{"hideNavbar", "true" },
{"user_account_info", "{\"displayName\":\""+mauiApplicationViewModel.UserAccount.DisplayName+"\"," +
"\"employeeId\":"+mauiApplicationViewModel.UserAccount.EmployeeId+"," +
"\"employeeName\":\""+mauiApplicationViewModel.UserAccount.EmployeeName+"\"," +
"\"expires\":\""+mauiApplicationViewModel.UserAccount.TokenDateExpiration.ToString("o")+"\"," +
"\"token\":\""+mauiApplicationViewModel.UserAccount.AccessToken+"\"," +
"\"settings\":"+mauiApplicationViewModel.UserAccount.Settings+"}"},
};
}
public string? Url { get; protected set; }
public Dictionary<string, string> LocalStorage { get; }
}
protected override void OnConnected(EventArgs e)
{
base.OnConnected(e);
UserAccount = _request.Result;
TaskTabViewModel = ScopedServices.GetRequiredService<TaskTabViewModel>();
SearchTaskTabViewModel = ScopedServices.GetRequiredService<SearchTaskTabViewModel>();
//TODO: add other tabs
Application.Messenger.Send(NavigationMessangerPage.Home);
}
After authorization, I create ViewModels instances. When the MainPage is first rendered, these ViewModel==null. Next, notification occurs and works out OnPropertyChange(nameof(TaskTabViewModel)). But the binding to a non-empty element does not change after notification. base.OnBindingContextChanged(); triggered only on the first render.
<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Oss.Maui"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="Oss.Maui.MainPage"
xmlns:res="clr-namespace:Oss.Localization;assembly=Oss.Localization"
xmlns:controls="clr-namespace:Oss.Maui.Controls;assembly=Oss.Maui.Controls"
xmlns:loginView="clr-namespace:Oss.Maui.Views.Logins;assembly=Oss.Maui.Views"
xmlns:templateView="clr-namespace:Oss.Maui.Views.Tabs;assembly=Oss.Maui.Views"
xmlns:vm="clr-namespace:Oss.ViewModels;assembly=Oss.ViewModels"
Shell.NavBarIsVisible="True"
Shell.TabBarIsVisible="False"
Shell.TitleColor="Transparent"
Shell.NavBarHasShadow="False"
x:DataType="vm:MauApplicationViewModel"
BackgroundColor="{DynamicResource PageBackgroundColor}">
<ShellItem Route="login" FlyoutItemIsVisible="False">
<ShellContent ContentTemplate="{DataTemplate loginView:LoginView}"/>
</ShellItem>
<FlyoutItem Route="main" FlyoutDisplayOptions="AsMultipleItems">
<ShellContent Title="{res:Translate TaskTabTitle}" Icon="home.png">
<templateView:BaseTabView BindingContext="{Binding TaskTabViewModel, Mode=TwoWay}"></templateView:BaseTabView>
</ShellContent>
<ShellContent Title="{res:Translate SearchTaskTabTitle}" Icon="list.png">
<templateView:BaseTabView BindingContext="{Binding SearchTaskTabViewModel, Mode=TwoWay}"></templateView:BaseTabView>
</ShellContent>
</FlyoutItem>
</Shell>
How can I show tabs only after authorization, or update the binding?
UPDATE:
Ad TaskTabViewModel
private TaskTabViewModel _taskTabViewModel;
public TaskTabViewModel TaskTabViewModel
{
get => _taskTabViewModel;
set
{
SetValue(ref _taskTabViewModel, value);
}
}
ViewModel.SetValue
protected bool SetValue<T>(ref T property, T value, [CallerMemberName] string propertyName = null)
{
return SetValue(ref property, value, propertyName, null);
}
protected bool SetValue<T>(ref T property, T value, string propertyName, Action action)
{
if (Equals(property, value))
return false;
property = value;
NotifyPropertyChanged(propertyName);
if (action != null)
action();
return true;
}
Upvotes: 2
Views: 862
Reputation: 14594
I can't ensure the problem is the PropertyChangedEventHandler can work for the binding context of the content page or not. But I have checked the source code and found that there is only one BindableProperty named ContentProperty in the page. So the binding context is not a bindable property.
If you want to set the BaseTabView's binding context after getting the instance of the viewmodel. You can try the following code.
TaskTabViewModel = ScopedServices.GetRequiredService<TaskTabViewModel>();
Shell.Current.Items[1].Items[0].BindingContext = TaskTabViewModel;
// the first Items is flyoutitem which route is main and the second items is the BaseTabView
Upvotes: 1