如何让动态加载的未绑定命名 XAML 元素的实例彼此独立运行?

How to have dynamically loaded instances of unbound named XAML elements behave independently from each other?

我有一个 WPF 应用程序,我在其中将文档视图实例动态加载到 TabControl。该视图有一个 ToolBar 和一些 ToggleButtons,我用它来控制该视图中某些元素的可见性(仅显示相关元素):

<UserControl x:Class="MyProject.View.Views.DocumentView" ...>
    ...
    <ToolBar>
        <ToggleButton x:Name="togglePropInspector" ... />
        ...
    </ToolBar>
    ...
    <Border Visibility={Binding ElementName=togglePropInspector, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}">
        ...
    </Border>
</UserControl>

我发现这有点简洁,因为一切都在视图内处理,不需要向视图模型(或隐藏代码)添加代码。但是,问题是检查一个选项卡上的切换按钮现在会在视图的所有实例中检查它,而不仅仅是当前选项卡。这基本上适用于状态未以任何方式绑定到视图模型的所有元素。有没有无需向视图模型添加代码即可解决此问题的方法?

为了完整起见,这里是我如何加载视图的相关部分:

<TabControl ItemsSource="{Binding Documents}">
    <TabControl.Resources>
        <DataTemplate DataType="{x:Type viewModels:DocumentViewModel}">
            <local:DocumentView />
        </DataTemplate>
    </TabControl.Resources>
</TabControl>

TabControl 有一个用于所有 TabItem 实例的内容主机。当分配给 TabItem.Content 属性 的数据模型具有相同的数据类型时,那么 TabControl 将重用相同的 DataTemplate,这意味着相同的元素实例,仅更新为来自数据绑定的更改数据。

要更改重用控件的状态,您必须显式访问控件,或者通过临时更改 [=19= 的数据类型强制 TabControl 重新应用 ContentTemplate ]:

<TabControl SelectionChanged="TabControl_SelectionChanged" />
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  var tabControl = sender as TabControl;
  var tabItemContainer = tabControl.ItemContainerGenerator.ContainerFromItem(tabControl.SelectedItem) as TabItem;
  object currentContent = tabItemContainer.Content;
  tabItemContainer.Content = null;

  // Defer and leave the context to allow the TabControl to handle the new data type (null).
  // The content switch shouldn't be noticable in the GUI.
  Dispatcher.InvokeAsync(() => tabItemContainer.Content = currentContent);
}

您还可以为每个选项卡使用专用数据类型。这样 TabControl 会自动强制切换 DataTemplate.

最干净的解决方案是将 ToggleButton 绑定到数据模型。