处理高级数据模板中的数据上下文更改

Handling Data Context change in advanced Data Template

我正在用 WPF 编写 MDI 应用程序 - 文档显示在选项卡中。

由于选项卡显示完整的文档,TabControl 的 DataTemplate 显然相当复杂 - 包括 CodeBehind 中的一些 initialization/deinitialization 代码(没有 hack - 这只是我使用的控件所需要的,即 AvalonEdit)。但问题是,TabControl 重用了创建的 DataTemplate,当我更改活动文档时,仅替换了 DataContext - 省略了所有 initialization/deinitialization 过程,这些过程在 Loaded/Unloaded 事件中执行。

我想挂钩 DataContextChanged 事件,但有一个问题:

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.

(来源:https://docs.microsoft.com/pl-pl/dotnet/api/system.windows.frameworkelement.datacontextchanged?view=netframework-4.8

因此可能会发生,所有数据绑定都在没有 deinitialization/initialization 调用的情况下被刷新(包括 AvalonEdit 接收新文档),这将导致异常。

理想的解决方案是强制 TabControl 每次从 DataTemplate 实例化视图,但视图重用机制似乎是 WPF 中的一般规则(ContentControl 也使用它)。不太理想但仍然可靠的选择是捕获 DataContext 更改 - 但我必须在 DataContext 更改之前和之后可靠地调用代码,这似乎也不可能。

我该如何解决这个问题?如何在 WPF 中正确维护 (initialize/deinitialize) 具有复杂视图的文档?

请看我对以下问题的回答:

我提供了一个 explanation/theory 和一个工作示例,说明如何使用 x:Shared 属性 "fully refresh" 一个 DataTemplate 以及 [=12 的实现=](我发现两者都是确保生成新的 DataTemplate 所必需的)。

总结一下:

  1. DataTemplate 需要在 ResourceDictionaryx:Shared="False" 中。

  2. 需要使用 DataTemplateSelector 来提供关于需要 resource/template 的歧义,以确保当前的 DataTemplate 不会被持久化。