wpfmvvmservicetabcontrolcatel

ItemsSource from a service in a TabItem only loaded when this tab is selected a second time


I have a service that holds a List of objects.

I have a ViewModel with a property that is referencing this List:

public MyViewModel(IMyService myService)
{
    MyList = myService.TheList;
}

public List<Object> MyList { get { return GetValue...etc

This ViewModel is for the view named MyView, which is displayed in a TabItem, itself in a TabControl, none of which is the program's first view. MyView contains a ComboBox with its ItemsSource bound to MyList.

When the program is launched, myService.TheList is null. Later, it is loaded. From then, going in the tab displaying MyView shows an empty ComboBox. But switching TabItem and coming back eventually fires OnPropertyChanged, and the ComboBox is populated.

Why is OnPropertyChanged only fired the second time the view is displayed?


Solution

  • If your service lazy-loads (or at least at a later stage), you should implement events on your service to inform listeners that data has become available. Then you should do something like this on your view model.

    Note that this implementation also prevents memory leaks (since it handles both subscription and unsubscription from the service), which a lot of people forget when implementing view models.

    private readonly IMyService _myService;
    
    public MyViewModel(IMyService myService)
    {
        Argument.IsNotNull(() => myService);
    
        _myService = myService;
    }
    
    public List<Object> MyList { get; private set; }
    
    protected virtual async Task InitialyzeAsync()
    {
        _myService.ReceivedData += OnMyServiceReceivedData;
    
        UpdateData();
    }
    
    protected virtual async Task CloseAsync()
    {
        _myService.ReceivedData -= OnMyServiceReceivedData;
    }
    
    private void OnMyServiceReceivedData(object sender, EventArgs e)
    {
        UpdateData();
    }
    
    private void UpdateData()
    {
        MyList = new List<Object>(myService.TheList);
    }