【问题标题】:WPF Specified element is already the logical child of another element. Disconnect it firstWPF 指定元素已经是另一个元素的逻辑子元素。先断网
【发布时间】:2012-08-23 12:25:01
【问题描述】:

在将一堆 Frame 控件转换为更简单的 ContentControl 控件以在其逻辑父模型视图中托管子模型视图后,我最近开始收到异常“Specified element is already the logical child of another element. Disconnect it first."”。

在下面的示例中,注释掉的代码将阻止崩溃的发生:

<UserControl x:Class="GUI.Views.Scenario.PathogenRiskLiquidIngestionView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:ScenModels="clr-namespace:GUI.ViewModels.ScenarioModels">

    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Vertical">
            <DockPanel>
                <Label DockPanel.Dock="Left" Content="Risk Assessment Title"></Label>
                <TextBox DockPanel.Dock="Right" Text="{Binding RiskAssessmentTitle, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"></TextBox>
            </DockPanel>
            <DockPanel>
                <Label DockPanel.Dock="Left" Content="Risk Calculated"></Label>
                <ComboBox SelectedItem="{Binding RiskCalculated, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding RiskCalculatedOptions}"></ComboBox>
            </DockPanel>
            <DockPanel>
                <Label DockPanel.Dock="Left" Content="{Binding MinAcceptableInfectionRiskLabel}"></Label>
                <TextBox DockPanel.Dock="Right" Text="{Binding MinAcceptableInfectionRisk, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"></TextBox>
            </DockPanel>
        </StackPanel>
        <!--<GroupBox Header="Pathogens">
            <StackPanel Orientation="Vertical">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                    <Button Content="Add Pathogen" Command="{Binding AddPathogen}"></Button>
                    <Button Content="Remove Pathogen" Command="{Binding RemovePathogen}" CommandParameter="{Binding SelectedIndex, ElementName=PathogenList}"></Button>
                </StackPanel>
                <ListView Name="PathogenList" ItemsSource="{Binding PathogensPresentViews}" Tag="{Binding}" BorderThickness="0" Background="Transparent">
                    <ListView.ItemTemplate>
                        <DataTemplate DataType="{x:Type ScenModels:PathogenPresentIngestViewModel}">
                            <ContentControl Content="{Binding}"></ContentControl>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>
        </GroupBox>
        <GroupBox Header="Receptor Characteristics">
            <StackPanel Orientation="Vertical">
                <ContentControl Content="{Binding ReceptorVolumeLiquidIngestedPerEventView}"></ContentControl>
                <ContentControl Content="{Binding ExposuresView}"></ContentControl>
            </StackPanel>
        </GroupBox>-->
    </StackPanel>
</UserControl>

在搜索这种异常后,最常见的原因似乎是一些不正确的样式,但是在这个应用程序中,我还没有为任何元素设置样式。有人可以告诉我可能导致此异常的原因吗?

谢谢, 亚历克斯。

【问题讨论】:

  • 另外值得一提的是,这似乎是导致此错误的唯一视图,并且在其他不会导致此错误的视图中有非常相似的 XAML。
  • 说真的,这个错误很容易理解,如果一个常见的原因是样式无关紧要,你可以很容易地推断出是什么原因导致的,并查看相关的代码部分。
  • 当元素已经作为子元素添加到某处时会发生异常,因此关键位置是:引用 UI 元素的位置以及以编程方式从树中添加和删除 UI 元素的位置。像{Binding ExposuresView} 这样的东西只会叫树冲突,你甚至不应该在数据中引用视图。我不能告诉你问题到底出在哪里(你应该是追踪它的人)。
  • 我很抱歉,但我不认为它像你所说的那么简单,无论如何我看不到这些观点中的一个最终成为多个元素的逻辑子元素,这就是为什么我有难以追踪。
  • 好吧,尽管如此,你还是设法做到了这一点,如果你有适当的模型视图分离,你就不会陷入困境......

标签: wpf xaml .net-4.0


【解决方案1】:

如果不了解所有底层对象是什么,我只能猜测......

这里有一些真的很可疑:

<ListView Name="PathogenList" ItemsSource="{Binding PathogensPresentViews}" Tag="{Binding}" BorderThickness="0" Background="Transparent">
    <ListView.ItemTemplate>
        <DataTemplate DataType="{x:Type ScenModels:PathogenPresentIngestViewModel}">
            <ContentControl Content="{Binding}"></ContentControl>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

正如 cmets 中所提到的,您甚至不应该遇到绑定到 *Views 的情况,视图模型不应该有对视图的引用,而应该只有视图模型。如果你像这样违反它,那么遵循模型-视图-分离模式就没有什么意义了。

无论如何,当您绑定到大概是视图和 UI 元素时,这里可能会发生一些不受欢迎的事情:

  1. DataTemplate 已创建:视图已添加到 ContentControl -> 现在是控件的子项
  2. ListView “搞砸DataTemplate,我可以按原样显示这个项目。”(因为它是一个视图,它不应该是)。
  3. ListView 将项目(视图,它是 ContentControl 的子项)添加到 ItemsPanel
  4. 哎呀!

但可能不是这样,WPF 应该比这更聪明,那么这个怎么样:在PathogensPresentViews 列表中对同一个实例的多个引用?

或者在两个地方使用相同的视图模型,创建两个视图,它们都尝试显示相同的 UI 元素列表?

无论实际情况如何,您不应该对抗症状而是对抗疾病,这很可能是您的视图模型包含视图。

【讨论】:

  • 我明白你对观点的看法,但这是一个非常神秘的问题,因为它在某些情况下工作正常,但在非常特定的情况下会引发此异常,但不知道为什么。我将尝试重构我的视图结构以绑定数据上下文而不是整个视图。
  • @AlexHopeO'Connor:许多 UI 操作都是异步的,因此可能会产生一些未定义的行为。出于好奇,您是否使用任何 MVVM 框架?
  • 是的,我有一个域模型,我在其上构建了一堆视图模型,然后我为视图模型制作了一堆视图,其中包含视图模型中的所有程序逻辑。我的视图模型中包含视图的原因是因为我编写的库系统要求视图在其构造函数中采用模型参数,但我可以为每个视图添加第二个无参数构造函数以允许它们成为由其他视图在 XAML 中创建。
  • @AlexHopeO'Connor:我的意思是如果你使用像 Prism 或 Caliburn 这样的东西。无论如何,您不应该需要传递对视图的引用,当视图放置在需要它的位置并且它将 VM 作为 DataContext 获取时,这会自动发生。整个视图创建业务很糟糕,我自己通过使用 implicit DataTemplates 将其完全委托给 WPF。
  • 但在某些情况下,视图需要基于磁盘中的文件创建,这意味着在这些情况下我实际上无法编写 XAML 来绑定数据上下文,最简单的方法是通过构造函数。
猜你喜欢
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2012-11-17
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多