Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error "Specified element is already the logical child of another element"?

Tags:

mvvm

wpf

xaml

I have a TabControl and each Tab can contain the same UI but with different data. In any tab the user can click on a button and bring up a popup. This sets a Style property to the ViewModel telling it what style to use for the popup UI. The Style gets bound to a custom DependecyProperty that is attached to a custom PopupUserControl. My problem is that when the a 2nd copy of the popup gets opened in another tab, I get the following error (regardless of what Style is applied):

Specified element is already the logical child of another element. Disconnect it first.

ButtonClick command:

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

This triggers a PropertyChange event on the Style

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

Which triggers the OnPropertyChanged event in the ViewModelBase

protected virtual void OnPropertyChanged(string propertyName)
{
    this.VerifyPropertyName(propertyName);

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

The error occurs at line handler(this, e); in the ViewModelBase

EDIT

The TabItem contains a Canvas and a bunch of panels that can be added/removed/moved/etc. Each Panel has its own resource directory. From within the Panel I can set the PopupStyle just fine and it gets applied without a problem. The Style used within the panels is also defined in the PanelResourceDictionary.

The main difference with the one that is failing and the ones succeeding is the Style is located in different locations.

EDIT #2 Style that is failing - LookupDialog is a custom 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>

Style that Works:

<!-- 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>
like image 292
Rachel Avatar asked Oct 26 '10 14:10

Rachel


1 Answers

My problem was I was setting the Content in my Style, and Content cannot have more then one logical parent. I needed to move that to a Template instead. Since I didn't want to lose the base style, I set the content in the ContentTemplate property of the HeaderedContentControl (DraggablePanel in my code).

+1 to Davy anyways for helping me walk through this.

like image 73
Rachel Avatar answered Nov 15 '22 23:11

Rachel