Search code examples
c#wpfdatacontext

Handling Data Context change in advanced Data Template


I'm writing an MDI application in WPF - documents are being displayed in tabs.

Since a tab displays the complete document, DataTemplate for TabControl is obviously quite complex - including some initialization/deinitialization code in CodeBehind (no hacks - this is simply required by controls I use, namely AvalonEdit). The problem is though, that TabControl reuses the created DataTemplate and when I change active document, only DataContext is replaced - omitting all initialization/deinitialization procedures, which are performed in Loaded/Unloaded events.

I thought of hooking DataContextChanged event, but there's a catch:

When the DataContext for an element changes, all data-bound properties on this element are potentially affected. This applies to any elements that are child elements of the current element in the logical tree, which inherit the data context, and also the current element itself. All such existing bindings must re-interpret the new DataContext and will reevaluate the binding results. The data binding engine is not deterministic about the order of these reevaluations, relative to the raising of the DataContextChanged event. The reevaluations can occur before the event, after the event, or in any mixture.

(source: https://learn.microsoft.com/pl-pl/dotnet/api/system.windows.frameworkelement.datacontextchanged?view=netframework-4.8)

So it may happen, that all data bindings are refreshed (including AvalonEdit receiving new document) without deinitialization/initialization calls, what will result in exception.

The ideal solution would be to force TabControl instantiate the view each time from DataTemplate, but it seems like the view-reusing mechanism is a general rule in WPF (ContentControl uses it as well). The less ideal, but still reliable option would be to capture DataContext changes - but I would have to be reliably call code before and after DataContext change and it seems like it is not possible either.

How can I solve this problem? How can I maintain properly (initialize/deinitialize) document with complex view in WPF?


Solution

  • Please see my answer to the following question:

    https://stackoverflow.com/a/47763600/5314530

    I've provided an explanation/theory and a working example of how to "fully refresh" a DataTemplate using the x:Shared attribute as well as an implementation of DataTemplateSelector (I found that both were necessary to ensure a new DataTemplate was generated).

    To summarise:

    1. The DataTemplate needs to be in a ResourceDictionary with x:Shared="False".

    2. A DataTemplateSelector needs to be used to provide ambiguity as to which resource/template is required, in order to ensure the current DataTemplate is not persisted.