Search code examples
c#wpfmvvm

I am coupling my view model to the MessagingCenter of the CommunityToolkit.MVVM?


As context, I explain my case. I have a view model and I would like to notify to the view when the selected item is selected in the view model, beacuse I want that the list view scroll to the selected item.

One option it is to use MessagingCenter of the toolkit, that is used in the view model in this way:

private void Refresh(IEnumerable<MyType> paramItems)
{
    MyCollection.Clear();

    foreach (MyType iterator in paramItems.OrderByDescending(x => x.MyDate))
    {
        MyCollection.Add(iterator);
    }
    // I get the first item in Collection
    MyType item = MyCollection[0];
    MessagingCenter.Send<MainPageViewModel,MyType>(this, "Hi",item);
}

And in the view, in code behind, I subscribe to this message:

public MainPage()
{
    InitializeComponent();
    this.BindingContext = new MainPageViewModel();
    MessagingCenter.Subscribe<MainPageViewModel,MyType>(this, "Hi", (sender,Item) =>
    {       
        //we set the x:Name="mylistview" for ListView in xaml
        mylistview.ScrollTo(Item, ScrollToPosition.Start,false);
    });
}

In the view model, I am using the MessagingCenter of the toolkit, so I thinking that this are adding dependencies to the view model to the toolkit.

So in the code behind I have to add code to subscribe to the method, I was thinking in another solution:

The view:

public partial class MainPage : ContentPage
{
    MainPageViewModel _viewModel;



    public RegistroHorarioView(mainPageViewModel paramViewModel)
    {
        InitializeComponent();


        BindingContext = paramViewModel;
        _viewModel = paramViewModel;

        paramViewModel.PropertyChanged += OnProperyChangedInViewModel;
    }


    private void OnProperyChangedInViewModel(object? sender, PropertyChangedEventArgs e)
    {
        if(string.CompareOrdinal(e.PropertyName, nameof(_viewModel.MySelectedItem)) == 0)
        {
            this.MyListView.ScrollTo(_viewModel.MySelectedItem, ScrollToPosition.Start, false);
        }
    }
}

How the view model implements NotifyPropertyChanged, I can subscribe to this event and then check which property has changed and execute the code that I need for that case.

It is to have code in the code behind, but with the MessagingCenter I have to do the same.

And this is my view model:

private void Refresh(IEnumerable<MyType> paramItems)
{
    MyCollection.Clear();

    foreach (MyType iterator in paramItems.OrderByDescending(x => x.MyDate))
    {
        MyCollection.Add(iterator);
    }
    // I get the first item in Collection
    //MySelectedItem is the property of the view model for the selected item.
    MySelectedItem = MyCollection[0];
}

In this case I am not using the MessagingCenter, so I guess I am reducing the coupling of the view model to another resources.

But I don't know if it is a good option or it is better to use the MessagingCenter because it has advantages that I don't know.

Thanks.


Solution

  • You bascially use a messenger to avoid tight coupling between the publisher and the subscriber of a message at the expense of some additional complexity. The idea is that each component has a dependency on a single messenger instead of each and every other component it indirectly communicates with.

    If the view already has a strong dependency on the view model, as in the code you have posted, you might as well subscribing to the PropertyChanged event of the view model directly without involving a messenger.

    Just remember to explicitly unsubscribe from the event to avoid memory leaks in case the view model outlives the view.