question

mrw-4494 avatar image
0 Votes"
mrw-4494 asked pugthegreat answered

Trigger EventHandler of one ViewModel in another ViewModel

I have achieved desired result with MessagingCenter, but I have got an information from reading Xamarin articles that MessagingCenter is not the preferred way to trigger 30+ events. Additional to that I have to unsubscribe from MessagingCenter after action has been done. I want to have Settings page where I would have 30+ settings that have to be changed across whole application in different views. How I can inject SettingsViewModel into other ViewModels in Xamarin.Forms application?

SettingsViewModel.cs:

 namespace MessagingCenterApp.ViewModels
 {
   public class SettingsViewModel : BaseViewModel, ISettingsViewModel
   {
     public ICommand ChangeCommand { get; set; }
     public SettingsViewModel()
     {
       Title = "Settings";
    
       this.BoxColor = Color.Red;
    
       this.ChangeCommand = new Command(this.ChangeColor);
     }
    
     private void ChangeColor()
     {
       this.BoxColor = Color.FromHex(this.BoxColorS);
    
       MessagingCenter.Send<Object, Color>(this, "boxColor", this.BoxColor);
     }
    
     private Color _boxColor;
     public Color BoxColor
     {
       get => _boxColor;
       set
       {
         _boxColor = value;
         this.OnPropertyChanged();
       }
     }
    
     private string _boxColorS;
     public string BoxColorS
     {
       get => Preferences.Get("BoxColor", "#17805d");
       set
       {
         Preferences.Set("BoxColor", value);
         this.ChangeColor();
         this.OnSettingsChanged();
         this.OnPropertyChanged();
       }
     }
    
     public event EventHandler<SettingsChangedEventArgs> SettingsChanged;
     private void OnSettingsChanged() => this.SettingsChanged?.Invoke(this, new SettingsChangedEventArgs(this.Settings));
    
     public Settings Settings { get; private set; }
   }
 } 

HomeViewModel.cs:

 namespace MessagingCenterApp.ViewModels
 {
   public class HomeViewModel : BaseViewModel
   {
     public HomeViewModel()
     {
       this.Title = "Home";
    
       MessagingCenter.Subscribe<Object, Color>(this, "boxColor", (sender, arg) =>
       {
    
         System.Diagnostics.Debug.WriteLine("received color = " + arg);
         this.BoxColor = arg;
       });
    
       this.BoxColor = Color.Red;
    
       this.SettingsViewModel = new SettingsViewModel();
       this.SettingsViewModel.SettingsChanged += OnSettingsChanged;
     }
    
     private void OnSettingsChanged(object sender, SettingsChangedEventArgs e)
     {
       throw new NotImplementedException();
     }
    
     private Color _boxColor;
     public Color BoxColor
     {
       get => _boxColor;
       set
       {
         _boxColor = value;
         OnPropertyChanged();
       }
     }
    
     private ISettingsViewModel SettingsViewModel { get; }
   }
 }

Should I somehow do all in MainViewModel? I mean:

 namespace MessagingCenterApp.ViewModels
 {
   public class MainViewModel : BaseViewModel
   {
     public MainViewModel()
     {
       this.SettingsViewModel = new SettingsViewModel();
       this.HomeViewModel = new HomeViewModel(this.SettingsViewModel);
     }
    
     public SettingsViewModel SettingsViewModel { get; set; }
     public HomeViewModel HomeViewModel { get; }
   }
 }

Then initialized it in AppShell? I could not get this approach working.

Important! I don't want to use any MVVM framework! Only native behaviour.

dotnet-csharpdotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

pugthegreat avatar image
1 Vote"
pugthegreat answered pugthegreat edited

I suppose you have one instance of each ViewModel at runtime always created. This is not a common approach, typically ViewModels are instantiated as you navigate between ViewPages and destroyed when popped from the navigation stack.

If you do not want to use MessagingCenter, you could try to invoke events in MainViewModel from the SettingsViewModel, and then from the MainViewModel invoke events or call methods in the HomeViewModel.

You can use Xamarin Community Toolkit DelegateWeakEventManager and WeakEventManager so that GC cleans off the event handlers subscriptions without the need to unsubscribe them when you no longer need them.

With Dependency Injection, typically you don't inject ViewModels, usually you inject services into the constructors.

It is hard to understand your question without context. If you want to handle configuration changes for the whole application from the ViewModel, you can handle them directly, there is no need to pass the configuration changes to another ViewModel.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.