错误 "指定的元素已经是另一个元素的逻辑子元素"?

13
我有一个TabControl,每个选项卡都可以包含相同的UI但具有不同的数据。在任何选项卡中,用户都可以单击按钮并弹出一个窗口。这将设置Style属性到ViewModel,告诉它使用哪种样式来显示弹出UI。Style绑定到自定义DependecyProperty,该属性附加到自定义PopupUserControl。我的问题是,当第二个弹出窗口在另一个选项卡中打开时,无论应用何种样式,我都会收到以下错误消息:

指定的元素已经是另一个元素的逻辑子级。请先断开连接。

ButtonClick命令:

MyViewModel vm = ((Button)sender).DataContext as MyViewModel;
if (vm != null)
{
    Style popupStyle = (Style)Application.Current.FindResource("SomePopupStyle");
    vm.EditPanelStyle= popupStyle ;
}

这将在样式上触发一个PropertyChange事件。

public Style EditPanelStyle
{
    get { return _editPanelStyle; }
    set
    {
        if (_editPanelStyle != value)
        {
            _editPanelStyle = value;
            OnPropertyChanged("EditPanelStyle");
        }
    }
}

触发ViewModelBase中的OnPropertyChanged事件。
protected virtual void OnPropertyChanged(string propertyName)
{
    this.VerifyPropertyName(propertyName);

    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null)
    {
        var e = new PropertyChangedEventArgs(propertyName);
        handler(this, e);
    }
}

错误发生在ViewModelBase中的handler(this, e);行。 编辑 TabItem包含一个Canvas和一堆可以添加/删除/移动等的面板。每个面板都有自己的资源目录。从面板内部,我可以很好地设置PopupStyle,并且没有问题地应用它。在面板中使用的样式也在PanelResourceDictionary中定义。
失败的样式与成功的样式之间的主要区别是它们位于不同的位置。 编辑 #2 失败的样式-LookupDialog是自定义的WPF UserControl。
<!-- Popup Style for LookupDialog -->
<Style x:Key="LookupDialogBaseStyle" TargetType="{x:Type localControls:DraggablePanel}" BasedOn="{StaticResource GenericPopupStyle}">
    <Setter Property="Canvas.Left" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualWidth, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.25}" />
    <Setter Property="Canvas.Top" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualHeight, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.3}" />
    <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualWidth, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.5}" />
    <Setter Property="Height" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualHeight, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.4}" />

    <!--<Setter Property="localControls:PopupPanel.PopupEnterKeyCommand" Value="{Binding Path=SaveCommand}" />-->
    <Setter Property="localControls:PopupPanel.PopupEscapeKeyCommand" Value="{Binding Path=CancelCommand}" />

    <Setter Property="Header" Value="{Binding Path=Header}" />
    <Setter Property="localControls:PopupPanel.BackgroundOpacity" Value="0" />

    <Setter Property="Content">
        <Setter.Value>
            <localControls:LookupDialog 
                DataContext="{Binding}"
                BorderBrush="{StaticResource DarkColor}" />
        </Setter.Value>
    </Setter>
</Style>

<!-- Base Style for a Popup (DraggablePanel) -->
<Style x:Key="GenericPopupStyle" TargetType="{x:Type localControls:DraggablePanel}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type localControls:DraggablePanel}">
                <Border Height="{TemplateBinding Height}" Width="{TemplateBinding Width}">
                    <DockPanel>
                        <!-- Header -->
                        <Border 
                            DockPanel.Dock="Top"
                            MinHeight="20"
                            Background="{DynamicResource TabItem_BackgroundBrush_Unselected}"
                            BorderBrush="{StaticResource DarkColor}"
                            BorderThickness="1"
                            CornerRadius="5,5,0,0"
                            Padding="2,3,2,2"
                            SnapsToDevicePixels="True"
                            >

                            <ContentPresenter x:Name="PART_DraggablePanelHeader" ContentSource="Header" />
                        </Border>

                        <!-- Content -->
                        <Border Background="{StaticResource DefaultBackground}" 
                                BorderBrush="{StaticResource DarkColor}" 
                                BorderThickness="1,0,1,1"
                                SnapsToDevicePixels="True">
                            <ContentPresenter ContentSource="Content" />
                        </Border>
                    </DockPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

实用的样式:

<!-- Example Popup Style for a Panel -->
<Style x:Key="AgentDesktop_NotesPanelPopupStyle" TargetType="{x:Type ContentControl}">
    <Setter Property="Canvas.Left" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualWidth, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.2}" />
    <Setter Property="Canvas.Top" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualHeight, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.32}" />
    <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualWidth, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.6}" />
    <Setter Property="Height" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type localControls:PopupPanel}}, 
        Path=ActualHeight, Converter={StaticResource PercentToDoubleConverter}, ConverterParameter=.36}" />

    <Setter Property="localControls:PopupPanel.PopupEnterKeyCommand" Value="{Binding Path=SaveCommand}" />
    <Setter Property="localControls:PopupPanel.PopupEscapeKeyCommand" Value="{Binding Path=HidePopupCommand}" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <!-- Control Template removed to make this easier to read, but it's created from standard WPF controls with nothing special -->
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
3个回答

20

我的问题是我在我的样式中设置了Content,但Content不能有多个逻辑父级。我需要将其移动到Template中。由于我不想失去基本样式,因此我将内容设置在HeaderedContentControl(我的代码中的DraggablePanel)的ContentTemplate属性中。

无论如何,Davy帮助我解决了这个问题。


似乎每个具有内容的控件也需要独特的资源。至少我的图片需要这样一个样式,以更改用于两个切换按钮的图像。 - Dave
@Dave 要么是独特的,要么是某种模板。ControlTemplate、DataTemplate、ContentTemplate等。 - Rachel

8

请确保您正在创建一个新的选项卡对象,并且不要尝试第二次将相同的选项卡插入选项卡控件中。一个控件只能有一个父级,问题似乎是您正在尝试将选项卡插入两个不同的容器中,或更可能是在同一个选项卡控件中插入两次。


这肯定是一个独立的TabControl。让我感到沮丧的原因之一是我已经成功地以完全相同的方式从TabControl内部设置了PopupStyle,唯一的区别是这个弹出式菜单是由TabControl本身设置而不是从其子元素内部设置的。嗯,我会在我的问题中详细阐述这一点。 - Rachel
@Rachel,你能展示一下EditPanelStyle跟什么绑定了吗?我认为你所展示的代码并不是直接导致错误的地方。如果你没有显式处理PropertyChanged事件的任何代码,则错误很可能出现在XAML侧的数据绑定中。 - Davy8
我认为你是对的,我刚刚在运行一些测试,似乎是样式本身引起了问题,而不是代码。我会发布这个样式。 - Rachel
我想我刚刚弄清楚了...这是因为我正在将“内容”应用于失败的样式中,而我正在新样式中应用“模板”。 而内容不能添加到两个不同的逻辑父级。 现在我只需要找到一种重写它的方法...谢谢你帮助我解决问题! - Rachel
不客气,很抱歉我不能提供更直接的帮助,因为我已经几个月没有在WPF上工作了。 - Davy8
无论如何加1。有人向我解释问题确实帮了我,因为这样我开始看到我的问题所在。 - Rachel

-1
如果不想阅读以上所有内容,简短的答案是:您需要将 XAML 中的 Content 更改为 Template(无论是样式还是直接声明 ContentControl)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接