Passing an observableObject to different ViewModels

Supermack

Member
Joined
Feb 4, 2023
Messages
9
Programming Experience
Beginner
Hello,

i am trying to have one entry for an User object. the properties of the user could be changed so i need to pass the user then need to also keep it up-to-date in the different views.

What i did currently :

in App.xalm.cs
C#:
Expand Collapse Copy
          public static Model.User LoggedUser = new();

In my Login Page i put a listener in order to have all my current user properties changes.
Then put affect it to my App.LoggedUser

LoginPageViewModel.cs
C#:
Expand Collapse Copy
           DocumentReference docRef = App.FirestoreDB.Collection("User").Document(userinfo.Info.Uid);
                    FirestoreChangeListener MyUserListener = docRef.Listen(snapshot =>
                    {

                        if (snapshot.Exists)
                        {
                            App.LoggedUser = (User)snapshot.ConvertTo<User>();
                        }

                    });

For the other viewmodels,
like below, i created an User object to receive the App.loggedUser

HomePageViewModel
C#:
Expand Collapse Copy
public partial class HomePageViewModel : BaseViewModel
{
    [ObservableProperty]
    Model.User user;

    public HomePageViewModel()
    {
        this.user = App.LoggedUser;      
    }

  
    private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
       User = App.LoggedUser;     
    }

}
Any advices to do it in a proper way please. i am just a beginner try to do his first app with Firebase+Maui.net.
Is there a way to bind views directly with the App.LoggedUser ?
 
Last edited by a moderator:
Welcome to the forum. In the future, please post your code in code tags. The easiest way to do that is to use the button on the toolbar that looks like </>.
 
Anyway, to answer your question, you would typically just dependency injection and pass in the App.LoggedUser to both view models. There is nothing blocking you from having a model shared between view models, and having view models shared between multiple views.
 
Anyway, to answer your question, you would typically just dependency injection and pass in the App.LoggedUser to both view models. There is nothing blocking you from having a model shared between view models, and having view models shared between multiple views.

Hello,
all my views and viewmodels have been declared in the MauiProgam.cs file

C#:
Expand Collapse Copy
 builder.Services.AddSingleton<IConnectivity>(Connectivity.Current);
        builder.Services.AddSingleton<IGeolocation>(Geolocation.Default);
        builder.Services.AddSingleton<IMap>(Map.Default);

        builder.Services.AddSingleton<LoginPageViewModel>();
        builder.Services.AddSingleton<LoginPage>();
        builder.Services.AddSingleton<LoginService>();

        builder.Services.AddSingleton<RegisterPageViewModel>();
        builder.Services.AddSingleton<RegisterPage>();

        builder.Services.AddTransient<UserProfil>();
        builder.Services.AddTransient<UserProfilViewModel>();

My views are not updated, i probably missed something or did something wrong.
Is there a way to bind views directly with App.LoggedUser ?
 
The first step is to make all of your view models constructors to take a Model.User parameter. For example:
C#:
Expand Collapse Copy
public HomePageViewModel(Model.User user)
{
    this.user = user;
}

Then the next step is to register the an instance of the Model.User:
C#:
Expand Collapse Copy
builder.Services.AddSingleton<Model.User>(new Model.User());

That's for passing in the current know instance at the time of configuring all the services. The main problem is that you are using your App.LoggedUser like a global variable. You'll need to somehow propagate that new value that you pick up from your listener to everybody who has a reference to the old instance.

Personally, I would just wrap the Model.User class. So the only updates would happen within class, and it would fire INotifyPropertyChanged events when an update does happen. All the interested view models would register for that change event so that they would know pick up the new values.
 
The first step is to make all of your view models constructors to take a Model.User parameter. For example:
C#:
Expand Collapse Copy
public HomePageViewModel(Model.User user)
{
    this.user = user;
}

Then the next step is to register the an instance of the Model.User:
C#:
Expand Collapse Copy
builder.Services.AddSingleton<Model.User>(new Model.User());

That's for passing in the current know instance at the time of configuring all the services. The main problem is that you are using your App.LoggedUser like a global variable. You'll need to somehow propagate that new value that you pick up from your listener to everybody who has a reference to the old instance.

Personally, I would just wrap the Model.User class. So the only updates would happen within class, and it would fire INotifyPropertyChanged events when an update does happen. All the interested view models would register for that change event so that they would know pick up the new values.

Hello,
thank you for your advices.

i managed to do it with messenger

WeakReferenceMessenger.Default.Register(this);:
Expand Collapse Copy
 WeakReferenceMessenger.Default.Register<UpdateLoggerUserMessage>(this);

i don't know if it's the best way but for the moment it works ;)
 
Back
Top Bottom