0

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.

Álvaro García
  • 18,114
  • 30
  • 102
  • 193
  • I would use a behavior. If you search round a bit you'll likely find other implementations but here's one. https://stackoverflow.com/questions/8827489/scroll-wpf-listbox-to-the-selecteditem-set-in-code-in-a-view-model – Andy Apr 12 '23 at 19:50

1 Answers1

1

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.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Thanks for the help and the advise to don't forget to unsubscribe the event in the view. In this case, this should to be in the Dispose() method of the view? Should the view to implement the IDisposable interface? – Álvaro García Apr 13 '23 at 10:16
  • It depends how you load and unload the views. WPF won't call `Dispose()` for you so a better idea may be to unregister when the `Unloaded` event for the view is raised. – mm8 Apr 13 '23 at 14:20