Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
740
LoadLayout() failure: Specified element is already the logical child of another element.
posted

I have a XamDockManager control with MDI-style ContentPanes.  My tabs are bound.  I am using Attached Properties to manage the tabs.  I am using using Dependency Properties to handle loading and saving the layout. 

On start up everything works as expected.  My problem starts when I tear off one of my previously tabbed panes.  SaveLayout() work correctly.  If I shut down the app and restart it the load fails during xamDockManager.LoadLayout(path_to_saved_layout).  

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

If I leave all of my bound, MDI-style panes as-is on start-up, there are no problems reloading the layout original layout.  Tearing off non-bound panes, doesn't cause any problems either.  

This seems to me to be a sequencing problem.  The tab already exists before the XamDockManager.Loaded Event which is what kicks off LoadLayout().  But I don't know what the final layout will be until I've applied the saved layout, so I don't know which content panes go where.  More specifically, I don't know which content panes should be orphaned before I load the layout.  I suppose I could crack open the XML file and manually parse the layout generated by LoadLayout() but that seems counter-productive.  

Any suggestions on how to get around this problem while still allowing my users the ability to save their custom layouts?

Parents
  • 54937
    Offline posted

    This seems to be a bug in your code. You're repopulating the tabgroup's Items collection with all the items while the layout is being loaded even though some of those items were reparented elsewhere as part of the loadlayout. I think if you set your layoutApplied flag to true before calling LoadLayout (in your LoadPaneLayout method) this could be avoided. Also you have a bug in that same TabGroupContentChangedHandler where you are still adding items even if the layoutApplied is true; since you don't have the indented code in a block only the clear call is conditional to the !layoutApplied check. So instead of:

       if (!layoutApplied)
        tabGroupPane.Items.Clear();
        foreach (var module in modules)
         if (module.ContentPane.Parent == null)
          tabGroupPane.Items.Add(module.ContentPane);

    [./code]

    It should be:

    [code]   if (!layoutApplied)
       {
        tabGroupPane.Items.Clear();
        foreach (var module in modules)
         if (module.ContentPane.Parent == null)
          tabGroupPane.Items.Add(module.ContentPane);
       }

    Here's the callstack I'm seeing that is causing the issue:

      PresentationFramework.dll!System.Windows.Controls.ItemCollection.Clear() Line 268 + 0xb bytes C#
      DockManager.Ui.dll!DockManager.Ui.Behaviors.XamDockManagerBehaviors.TabGroupContentChangedHandler(System.Windows.DependencyObject obj, System.Windows.DependencyPropertyChangedEventArgs e) Line 239 + 0x18 bytes C#
      WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Line 2035 + 0x2c bytes C#
      PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) Line 2067 + 0x22 bytes C#
      WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) Line 1739 + 0x22 bytes C#
      WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) Line 1553 + 0xb4 bytes C#
      WindowsBase.dll!System.Windows.DependencyObject.InvalidateProperty(System.Windows.DependencyProperty dp) Line 1206 + 0x74 bytes C#
      PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Invalidate(bool isASubPropertyChange) Line 1226 + 0x12 bytes C#
      PresentationFramework.dll!System.Windows.Data.BindingExpression.TransferValue(object newValue, bool isASubPropertyChange) Line 1506 C#
      PresentationFramework.dll!System.Windows.Data.BindingExpression.Activate(object item) Line 1044 C#
      PresentationFramework.dll!System.Windows.Data.BindingExpression.OnDataContextChanged(System.Windows.DependencyObject contextElement) Line 2312 + 0x9 bytes C#
      PresentationFramework.dll!System.Windows.Data.BindingExpression.HandlePropertyInvalidation(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs args) Line 2490 C#
      PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.OnPropertyInvalidation(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs args) Line 316 + 0x23 bytes C#
      PresentationFramework.dll!System.Windows.Data.BindingExpression.OnPropertyInvalidation(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs args) Line 280 + 0x21 bytes C#
      WindowsBase.dll!System.Windows.DependentList.InvalidateDependents(System.Windows.DependencyObject source, System.Windows.DependencyPropertyChangedEventArgs sourceArgs) Line 58 + 0x24 bytes C#
      WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) Line 1764 C#
      WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) Line 1553 + 0xb4 bytes C#
      PresentationFramework.dll!System.Windows.TreeWalkHelper.InvalidateTreeDependentProperty(System.Windows.TreeChangeInfo info, System.Windows.DependencyObject d, ref MS.Internal.FrameworkObject fo, System.Windows.DependencyProperty dp, System.Windows.FrameworkPropertyMetadata fMetadata, System.Windows.Style selfStyle, System.Windows.Style selfThemeStyle, ref System.Windows.ChildRecord childRecord, bool isChildRecordValid, bool hasStyleChanged, bool isSelfInheritanceParent) Line 356 + 0x1a9 bytes C#
      PresentationFramework.dll!System.Windows.TreeWalkHelper.InvalidateTreeDependentProperties(System.Windows.TreeChangeInfo info, System.Windows.FrameworkElement fe, System.Windows.FrameworkContentElement fce, System.Windows.Style selfStyle, System.Windows.Style selfThemeStyle, ref System.Windows.ChildRecord childRecord, bool isChildRecordValid, bool hasStyleChanged, bool isSelfInheritanceParent) Line 286 C#
      PresentationFramework.dll!System.Windows.FrameworkElement.InvalidateTreeDependentProperties(System.Windows.TreeChangeInfo parentTreeState, bool isSelfInheritanceParent) Line 530 + 0x39 bytes C#
      PresentationFramework.dll!System.Windows.FrameworkElement.OnAncestorChangedInternal(System.Windows.TreeChangeInfo parentTreeState) Line 415 + 0x1e bytes C#
      PresentationFramework.dll!System.Windows.TreeWalkHelper.OnAncestorChanged(System.Windows.DependencyObject d, System.Windows.TreeChangeInfo info) Line 169 + 0x3c bytes C#
      PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d) Line 422 C#
      PresentationFramework.dll!MS.Internal.PrePostDescendentsWalker<System.Windows.TreeChangeInfo>._VisitNode(System.Windows.DependencyObject d) Line 108 + 0xc bytes C#
      PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.VisitNode(System.Windows.FrameworkElement fe) Line 380 + 0xc bytes C#
      PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.VisitNode(System.Windows.DependencyObject d) Line 397 + 0x16 bytes C#
      PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkLogicalChildren(System.Windows.FrameworkElement feParent, System.Windows.FrameworkContentElement fceParent, System.Collections.IEnumerator logicalChildren) Line 201 + 0x2e bytes C#
      PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.WalkFrameworkElementLogicalThenVisualChildren(System.Windows.FrameworkElement feParent, bool hasLogicalChildren) Line 307 C#
      PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.IterateChildren(System.Windows.DependencyObject d) Line 92 + 0x9 bytes C#
      PresentationFramework.dll!System.Windows.DescendentsWalker<System.Windows.TreeChangeInfo>.StartWalk(System.Windows.DependencyObject startNode, bool skipStartNode) Line 66 + 0xb bytes C#
      PresentationFramework.dll!MS.Internal.PrePostDescendentsWalker<System.Windows.TreeChangeInfo>.StartWalk(System.Windows.DependencyObject startNode, bool skipStartNode) Line 69 + 0x11 bytes C#
      PresentationFramework.dll!System.Windows.TreeWalkHelper.InvalidateOnTreeChange(System.Windows.FrameworkElement fe, System.Windows.FrameworkContentElement fce, System.Windows.DependencyObject parent, bool isAddOperation) Line 135 + 0x12 bytes C#
      PresentationFramework.dll!System.Windows.FrameworkElement.ChangeLogicalParent(System.Windows.DependencyObject newParent) Line 336 C#
      PresentationFramework.dll!System.Windows.FrameworkElement.AddLogicalChild(object child) Line 205 + 0x13 bytes C#
      InfragisticsWPF4.DockManager.v10.3.dll!Infragistics.Windows.DockManager.DocumentContentHost.OnPanesCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 344 + 0xb bytes C#
      System.dll!System.Collections.ObjectModel.ObservableCollection<Infragistics.Windows.DockManager.SplitPane>.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 281 + 0x11 bytes C#
      InfragisticsWPF4.v10.3.dll!Infragistics.Collections.ObservableCollectionExtended<Infragistics.Windows.DockManager.SplitPane>.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 734 + 0xb bytes C#
      InfragisticsWPF4.DockManager.v10.3.dll!Infragistics.Windows.DockManager.QueuedObservableCollection<Infragistics.Windows.DockManager.SplitPane>.OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 56 + 0xb bytes C#
      InfragisticsWPF4.v10.3.dll!Infragistics.Collections.ObservableCollectionExtended<Infragistics.Windows.DockManager.SplitPane>.InsertItem(int index, Infragistics.Windows.DockManager.SplitPane item) Line 688 + 0x2b bytes C#
      mscorlib.dll!System.Collections.ObjectModel.Collection<Infragistics.Windows.DockManager.SplitPane>.Add(Infragistics.Windows.DockManager.SplitPane item) + 0x6a bytes 
      InfragisticsWPF4.DockManager.v10.3.dll!Infragistics.Windows.DockManager.LayoutManager.LoadLayout(Infragistics.Windows.DockManager.XamDockManager dockManager, System.IO.Stream stream) Line 483 + 0x13 bytes C#
      InfragisticsWPF4.DockManager.v10.3.dll!Infragistics.Windows.DockManager.XamDockManager.LoadLayout(System.IO.Stream stream) Line 2038 + 0xc bytes C#
      DockManager.Ui.dll!DockManager.Ui.Behaviors.XamDockManagerBehaviors.LoadPaneLayout(object sender) Line 153 + 0xe bytes C#
      DockManager.Ui.dll!DockManager.Ui.Behaviors.XamDockManagerBehaviors.XamDockManagerLoaded(object sender, System.Windows.RoutedEventArgs e) Line 102 + 0x8 bytes C#

  • 740
    posted in reply to [Infragistics] Matt Traynor

    Hi Matt,

    Sorry, I got pulled off on another issue for a few days.

    I saw the missing curly braces shortly after I posted the sample.  

    Right now, I've got everything "working" in my sample.  Recent challenges have been related to handling tabs that are grouped outside the original context.  When you close the group, only the top pane visibility is updated.  The others remain visibly when they aren't.  Our solution adds a event handler for ToolWindowLoaded then adding a nested handler for the e.WindowClosed event..  Inside the nested handler I'm updating each toolPaneWindow.Panes.Pane.Visibility = Collapsed.  

    One issue that has been a nagging problem is: what's the best way/time/place to save a layout when shutting down the app?  Via the attached property, I've wired up a handler for Unloaded.  It doesn't get called when I close my app.  Right now, I've got Save() calls inside .LayoutUpdated.RequestBringIntoView.  I am not thrilled about having identical code in two places.  My tests show that LayoutUpdated catches things like theme updates that RequestBringIntoView would miss.  But LayoutUpdated doesn't catch things related to the Active pane management.  As far as I can tell Unloaded gets called as the tabs are created, but it doesn't fire when you close the app.  

    Any suggestions?

    Thx,

    Ivan

Reply Children