-1

I'm writing an application on WPF using MVVM. I have a TabControl in my MainWindow, that binds its ItemSource to a list of ViewModels for the TabItems. The TabItems can be of a couple different types, and the corresponding views for a given type are selected from DataTemplates defined in the MainWindow. All works well on this part.

One of the views defined in the DataTemplates has a custom user control in it- a third-party control that I've extended with dependency properties:

public static readonly DependencyProperty ModelLayerListProperty = DependencyProperty.Register(
        "ModelLayerList", typeof(LayerKeyedCollection), typeof(ModelDesign), new FrameworkPropertyMetadata(default(LayerKeyedCollection), OnLayerListChanged));

        public static readonly DependencyProperty ModelBlockListProperty = DependencyProperty.Register(
        "ModelBlockList", typeof(List<Block>), typeof(ModelDesign), new FrameworkPropertyMetadata(default(List<Block>), OnBlockListChanged));

        public static readonly DependencyProperty ModelEntityListProperty = DependencyProperty.Register(
        "ModelEntityList", typeof(List<Entity>), typeof(ModelDesign), new FrameworkPropertyMetadata(default(List<Entity>), OnEntityListChanged));

One caveat is that these properties have to be set in a particular order- the layers have to be set first, the blocks second, entities last, otherwise the third-party control throws an exception.

The first time a tab is opened, the data is bound to these properties correctly and is displayed in the view as it should be. The problem arises whenever switching to another tab and then back- even though while examining the ViewModel itself during runtime, all properties appear to be set correctly, setting breakpoints in the dependency property changed callbacks show that the new values received in the event arguments are either null or default values for the type.

I am aware that the TabControl does not persist data in views while switching tabs, and while I've seen solutions that force the TabControl to cache data, I would like to render the data from the viewmodel when the tab is opened- we could be displaying a couple of gigabytes of data from the ViewModel, which could hog up memory really quick.

I am also aware that I can bind to the TabControl SelectionChanged event (and not break the MVVM pattern via interactions), however I am not sure how to go about reloading the correct data to the view- do I have to fetch it from my repository again or is there some way to reload/rebind the data from the ViewModel itself?

  • You can add bind command to your Initialized for tabsItems (UIelement + ViewModels). this way whenever they will be initialized, you can implement your loading data logic. However you have to keep in mind the tabsitem life cycle (https://learn.microsoft.com/en-us/dotnet/desktop/wpf/events/object-lifetime-events?view=netdesktop-7.0) – Demon Mar 13 '23 at 11:33
  • @Demon Thanks for the suggestion- apparently relying on the lifecycle was my bane- if you are switching between two tabs of the same template, lifecycle events are not called and the UI elements are reused. I really wish that it was documented better (https://stackoverflow.com/questions/4993159/why-do-tab-controls-reuse-view-instances-when-changing-tab) – Konradas Stonkus Mar 13 '23 at 12:13

1 Answers1

0

I've figured it out, and this answer seems to shed the most light on the issue. Apparently, even though normally the TabItem get unloaded when switching tabs, if you are switching between two tabs that have the same DataTemplate, the control gets reused (only the datacontext changes!), the lifecycle events are not called and unbound properties on the control persist. Creating bindings on the properties that you want reloaded seems to do the trick.