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#:
          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#:
           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#:
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#:
 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#:
public HomePageViewModel(Model.User user)
{
    this.user = user;
}

Then the next step is to register the an instance of the Model.User:
C#:
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#:
public HomePageViewModel(Model.User user)
{
    this.user = user;
}

Then the next step is to register the an instance of the Model.User:
C#:
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);:
 WeakReferenceMessenger.Default.Register<UpdateLoggerUserMessage>(this);

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