Loading Pane Content results in InvalidOperationException

4 posts, 1 answers
  1. Kareema
    Kareema avatar
    17 posts
    Member since:
    Aug 2011

    Posted 26 Jul 2012 Link to this post

    Hello

    Please refer to the telerik "Save/Load the Content of the Panes" docking topic. I'm trying to load the layout of my docking control in this way when navigating away and then returning to this screen to maintain view state. This page refers to the following piece of code:
    private void radDocking_ElementLoading( object sender, Telerik.Windows.Controls.LayoutSerializationLoadingEventArgs e )
    {
        var pane = e.AffectedElement as RadPane;
        if ( pane != null )
        {
            pane.Content = this.GetPaneContent( e.AffectedElementSerializationTag );
        }
    }

    I assume that "GetPaneContent" refers to some internal method in the code-behind which returns the content, whatever that control may have been before the content was saved. Since I am using MVVM and adding RadPanes and RadPaneGroups dynamically in my view model, I maintain a dictionary of the pane contents by the serialization tag that I assign to each one. This view model code is as follows:

    RadPaneGroup radPaneGroup = new RadPaneGroup { VerticalAlignment = VerticalAlignment.Top, VerticalContentAlignment = VerticalAlignment.Top };
                this.view.splitContainer.Items.Add(radPaneGroup);
                RadPane radPane = new RadPane
                                              {
                                                  Content = createdChartView,
                                                  CanUserClose = true,
                                                  Title = createdChartView.DisplayName,
                                              };
                RadDocking.SetSerializationTag(radPane, chartConfiguration.Id.ToString());
                RadDocking.SetSerializationTag(radPaneGroup, chartConfiguration.Id.ToString());
     
                radPaneGroup.Items.Add(radPane);
                this.hostedCharts.Add(chartConfiguration.Id, createdChartView);

    To explain, chartConfiguration.Id is a Guid which serves as a string tag and hostedCharts is a field of type Dictionary<Guid, ChartView>.
    I use this dictionary to get the ChartView when I reload the layout. ChartView is the content I want to reset as the content of the pane.

    My element loading event handler looks like this:

    private void RadDockingOnElementLoaded(object sender, LayoutSerializationEventArgs e)
            {
                RadPane newPane = e.AffectedElement as RadPane;
                if (newPane != null)
                {
                    ChartView chartView = ((ChartHostViewModel)this.DataContext).GetPaneContent(e.AffectedElementSerializationTag);
     
    // This entire section is to try to remove the chart from its parent all the way up the visual tree.
                    RadPane oldParentPane = (RadPane)chartView.Parent;
                    if (oldParentPane != null)
                    {
                        RadPaneGroup oldParentGroup = (RadPaneGroup)oldParentPane.Parent;
                        if (oldParentGroup != null)
                        {
                            RadSplitContainer oldSplitContainer = (RadSplitContainer)oldParentGroup.Parent;
     
                            if (oldSplitContainer != null)
                            {
                                oldSplitContainer.Items.Remove(oldParentGroup);
     
                            }
                            oldParentGroup.Items.Remove(oldParentPane);
                        }
                        oldParentPane.Content = null;
                    }
     
                    newPane.Content = chartView;
                    return;
                }
     
    // This section is here because the pane groups fill up the entire space if I leave it out (They seem to be aligned to Stretch)
                RadPaneGroup newPaneGroup = e.AffectedElement as RadPaneGroup;
                if (newPaneGroup != null)
                {
                    newPaneGroup.VerticalAlignment = VerticalAlignment.Top;
                    newPaneGroup.VerticalContentAlignment = VerticalAlignment.Top;
                }
            }

    Here's my concern:
    Firstly, if I remove the code to try to remove the ChartView from its parent, I get an InvalidOperationException saying to first disconnect the element before adding it to a new one on the line, "newPane.Content = chartView;" . It seems that the entire visual tree is still intact and reloading the screen creates new visual elements and adds these to the Docking component. Is this not memory intensive? Please note that this screen's (my screen, "ChartHostView")'s lifestyle is Transient and may be affecting the way it should work.

    Secondly, my pane groups are not being loaded in the state that I saved them in. Why is it necessary for me re-set their Vertical Alignment ?

    Please let me know if I am going about this the completely wrong way.
    Thank you.
  2. Kareema
    Kareema avatar
    17 posts
    Member since:
    Aug 2011

    Posted 26 Jul 2012 Link to this post

    Forgot to mention the third concern:

    If after I have reloaded the docking layout, I try to rerun the second code extract (ie, add more panes to the docking) I don't see the panes being added. Is this because the groups are being added to a different (old) split container that got removed from the document host or what?
  3. UI for WPF is Visual Studio 2017 Ready
  4. Kareema
    Kareema avatar
    17 posts
    Member since:
    Aug 2011
  5. Answer
    Miroslav Nedyalkov
    Admin
    Miroslav Nedyalkov avatar
    1718 posts

    Posted 30 Jul 2012 Link to this post

    Hello,

    Here is the answer we provided in the support thread:

    The GetPaneContent method is not something internal, but a method you should create in your code to find the correct content for the corresponding pane. By default we are using the contents which panes currently contain when the Load method is called using the SerializationTag to match the panes so in most cases you don't need to implement any custom logic to save and load the content except in the cases when panes are dynamically added to the docking control. In these cases you need to hook to the event and implement your custom logic for loading/finding the correct content for the pane.

    What the docking control does when you call the LoadLayout method is to detach all the docking components (Panes, Groups and SplitContainers) from one another and to store the ones that have SerializationTag set in a Dictionary by SerializationTag. After that it starts loading the Layout from the XML provided and when it finds an item with SerializationTag set it tries to find it in the dictionary and it succeeds it reuses the component. Please notice that in your case the chart is not removed from the Pane as the Docking control intends to reuse the Pane so if you are not reusing the pane you should clear its content manually (with your RemoveFromParent method).

    The reason why the pane is not visible when the AddPane method is called because all docking components which doesn't have SerializationTag set are removed from the Docking control and are not used anymore. My advise is to set SerializationTag to all Docking elements which have x:Name set. 

    Kind regards,
    Miroslav Nedyalkov
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Back to Top