Memory leak when displaying multiple RadDocking in ContentControl

7 posts, 0 answers
  1. Joel
    Joel avatar
    53 posts
    Member since:
    Sep 2013

    Posted 24 Jun 2015 Link to this post

    I am doing this in Caliburn Micro: 

    The view that host the Content Control:

    <Controls:TransitioningContentControl Grid.Row=" Grid.Column=" x:Name="ActiveItem"/>

     

    Test code in the view model - basically a timer that will assign TestSiteCollection[0] & TestSiteCollection[1] to ActiveItem repeatedly.

    private void tmrMemTest_Tick(object sender, EventArgs e)
    {
        if (isAddLimit)
        {
            ActiveItem = TestSiteCollection[1];               
            isAddLimit = false;
        }
        else
        {
            ActiveItem = TestSiteCollection[0];               
            isAddLimit = true;
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); // to see whether we have a leak or not.
        }
    }
     

    One of the TestSiteCollection elements is the RadDocking & its view look likes this.

    <telerik:RadDocking Grid.Row=" HasDocumentHost=" PanesSource="{Binding TestPanelCollection, Mode=OneWay}">

                <telerik:RadDocking.DockingPanesFactory>
                    <styles:CustomDockingPanesFactory/>
                </telerik:RadDocking.DockingPanesFactory>
                <telerik:RadSplitContainer InitialPosition="DockedLeft">
                    <telerik:RadPaneGroup  x:Name="leftGroup" telerik:RadDocking.SerializationTag="leftGroup"/>
                </telerik:RadSplitContainer>
                <telerik:RadSplitContainer InitialPosition="DockedRight">
                    <telerik:RadPaneGroup  x:Name="rightGroup" telerik:RadDocking.SerializationTag="rightGroup"/>
                </telerik:RadSplitContainer>
                <telerik:RadSplitContainer InitialPosition="DockedTop">
                    <telerik:RadPaneGroup x:Name="topGroup" telerik:RadDocking.SerializationTag="topGroup"/>
                </telerik:RadSplitContainer>
                <telerik:RadSplitContainer InitialPosition="DockedBottom">
                    <telerik:RadPaneGroup x:Name="bottomGroup" telerik:RadDocking.SerializationTag="bottomGroup"/>
                </telerik:RadSplitContainer>
    </telerik:RadDocking>

     

    CustomDockingPanesFactory:

    protected override RadPane CreatePaneForItem(object item)
    {
        var viewModel = item as TestPanelBase;
        if (viewModel != null)
        {
            var pane = viewModel.IsDocument ? new RadDocumentPane() : new RadPane();
            pane.DataContext = item;
            pane.Header = viewModel.Header;
            // When saving the layout, RadDocking control generates an xml schema for its elements and their position,
            // size and other properties.
            // We need to set a SerializationTag for each Pane. Otherwise, each time when loading,
            // a new Pane will be generated and we will lose the DataContext, which is not desirable.
            RadDocking.SetSerializationTag(pane, viewModel.Header);
            if (viewModel.ContentType != null)
            {
                pane.Content = Activator.CreateInstance(viewModel.ContentType);
            }
     
            return pane;
        }
     
        return base.CreatePaneForItem(item);
    }
     
     
    protected override void RemovePane(RadPane pane)
    {
        // A problem could exist if you hold a reference to the old content or it was declared in XAML.
        // There is one memory leak in the Docking control we are aware of -
        // if you are removing the whole pane and it was the last one in the group,
        // it is not destroyed before you add another pane in this group
        pane.ClearValue(RadDocking.SerializationTagProperty);
        // Removes the Pane from the RadDocking layout. By default clears the Header, Content, DataContext and call RemoveFromParent method.
        base.RemovePane(pane);
    }

     

    What i have observed is that every time ActiveItem is assigned, CreatePaneForItem() is called. I am suspecting that is the cause of the memory leak. 

    What can i do to prevent this multiple call to CreatePaneForItem()?

     

    p/s: i have cleaned up other misbehaving codes that have contributed to the memory leak & i am now stuck at this observation.

  2. Joel
    Joel avatar
    53 posts
    Member since:
    Sep 2013

    Posted 24 Jun 2015 Link to this post

    I probably should be asking why RemovePane() in the CustomDockingPanesFactory() is not being called to release the resources before RadDocking triggers a CreatePaneForItem() to render a next view?
  3. UI for WPF is Visual Studio 2017 Ready
  4. Vladi
    Admin
    Vladi avatar
    744 posts

    Posted 29 Jun 2015 Link to this post

    Hi Joel,

    Thank you for contacting us.

    We are not aware of such issues in the current version of the RadDocking control and its PanesSource feature. By design in order for the RadDocking control to be able to represent the PanesSouce collection of objects as RadPane instance either the default or a custom DockingPanesFactory will be used. When the PanesSource collection is directly bound to objects of RadPane or RadDocumentPane type the AddPane is called and when that collection is bound to objects of other types the CreatePaneForItem method will be called. When the RemovePane of the DockingPanesFactory of the control is called the RemoveFromParent method is internally called to fully remove the instance from the RadDocking control.

    Could you describe to us in greater details what the scenario of your project exactly is. From what we understand you have created a collection of "objects" that is being passed one by one to a TransitioningContentControl and one of those objects is a RadDocking control. When exactly is that control being remove or re added in order to experience the described memory issue. Is the entire control being removed and replaced by a different control or is the PanesSource collection bound to it being edited.

    If you could isolate the issues in a sample project and send it to us in a new support thread it would be very helpful in further investigating the scenario.

    Regards,
    Vladi
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  5. Joel
    Joel avatar
    53 posts
    Member since:
    Sep 2013

    Posted 29 Jun 2015 Link to this post

    I have a combo box which list 3 test sites. Each time the user select one test site, the entire content of the TransitioningContentControl is replaced. What happen is that each time the selection changed happens, only CreatePaneForItem() is called - which make sense, but no RemovePane() was triggered. 

     

    Once i have time, i will stripped off the project and post it up here. Meanwhile, any insight to this is helpful...

  6. Vladi
    Admin
    Vladi avatar
    744 posts

    Posted 01 Jul 2015 Link to this post

    Hi Joel,

    Thank you for the additional details.

    By design the RemovePane method of the DockingPanesFactory will be called each time an object is removed from the bound collection to the PanesSource property of the control. When the entire RadDocking control is removed from its parent what happens is that the bound collection is removed causing a "null" collection to be set to the PanesSource. This scenario is correctly handled by the control and the RemovePane method of the DockingPanesFactory will be called for each RadPane which was in the control before it was removed.

    I recorded a short video for you showing the described behavior in action. If we have missed something let us know.

    Regards,
    Vladi
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  7. Joel
    Joel avatar
    53 posts
    Member since:
    Sep 2013

    Posted 01 Jul 2015 Link to this post

    When the content in TransitioningContentControl is replaced, do i need to explicitly issue the RemovePane command to clean up the RadDocking resources (which was displayed prior to the replacement)? I am just hoping for that to happen "automatically". 
  8. Vladi
    Admin
    Vladi avatar
    744 posts

    Posted 06 Jul 2015 Link to this post

    Hi Joel,

    As mentioned before by design if the PanesSource of the RadDocking control has been set to a collection of objects and that collection is being edited (items are being removed or the collection is cleared) the RemovePane method of the control's DockingPanesFactory will be called. This method is explicitly called in such scenarios in order to correctly update the control of its current items. As mentioned before if the entire control is removed from its parent control the .NET framework itself will first remove the bound collection (making it null) which will be registered as a CollectionChanged event and the RadDocking control's DockingPanesFactory will be notified to call its RemovePane. This is not required in order to remove the control as it is actually being remove entirely but it is an effect caused by how the .NET framework handles the scenario.

    In the scenarios where the control is passed to a TransitionControl and is not explicitly removed from its parent control the RemovePane method will not be called. In such scenarios if there is not reference left to the old content of the TransitionControl any RadDocking control that was used as that old content will correctly be collected by the framework's garbage collector. In such scenario again the RemovePane will not be called because the bound collection to the PanesSource has not been explicitly changed. If you desire to have a peace of mind and want to manually clear the bound collection before the content of the TransitionControl is changed you could do it but have in mind that it will cause a visual effect as RadPane instances will be actually removed. In all of our tests for such manual removal step has not been required.

    I created and attached a sample project for you of the described approach, hope this is helpful in understanding how the DockingPanesFactory and its RemovePane method function.

    Regards,
    Vladi
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top
UI for WPF is Visual Studio 2017 Ready