tags:

views:

42

answers:

2

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>
+2  A: 

Make sure you're creating a new tab object and you're not trying to insert the same tab into the tab control a 2nd time. A control can only have 1 parent and it seems like the issue is you're trying to insert a tab into either 2 different containers, or more likely the same tab control twice.

Davy8
Its definitely a separate TabControl. Part of why I am so frustrated with this thing is I have successfully set the PopupStyle in this exact same way from inside the TabControl, the only difference is this popup is being set from the TabControl itself instead of from within its children. Hrrm I'll expand on this in my question
Rachel
@Rachel Can you show what's bound to EditPanelStyle? I don't think the code you showed is directly where the error lies. If you don't have any code explicitly handling the PropertyChanged event then the error is likely in the xaml-side databinding.
Davy8
I think you're right, I was just running some tests and it appears to be the Style itself causing the problem, not the code. I'll post the style
Rachel
I think I just figured it out.... its because I'm applying the `Content` in the failing Style, while I am applying `Template` in the new one. And Content cannot be added to two different logical parents. Now I just need to find a way to rewrite this.... thanks for helping me walk through it!
Rachel
You're welcome, sorry I couldn't help more directly, haven't actually worked in WPF for a couple months.
Davy8
+1 anyways. It helped me to have someone to explain the problem to because then I started to see where my problem was at
Rachel
+2  A: 

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.

Rachel