Question

Help with memory cleanup of editors

Posted 4 years ago by Avatar Craig - Varigence, Inc.
I’m having a problem with memory cleanup when using some Actipro editor controls and Actipro ribbon split buttons.

Background:

I have a WPF application that uses projects, similar to Visual Studio. Each project is represented by a ProjectViewModel object, which holds collections of other ViewModels, which in turn hold collections to other ViewModels, etc…

When a user opens a project, they can double click on items to open editors, which allow the user to edit information in the items. Each editor inherits from WPF Page and a NavigatorFrame is used to display a Page and navigate to other pages.

Scenario:

The trouble is that when a user closes a project, we expect the ProjectViewModel, and the ViewModels referencing it, to be freed by the garbage collector. However, there are many controls that use WPF dependency properties which hold references to our ViewModels, and don’t release those references when expected. Note that we expect to be able to leave our editors in memory (since databinding should allow us to reuse the same editor instance if the user opens another project). Thus, on project close, we’ve decided to call cleanup functions on our editors in order to clear DependencyProperties that are holding references.

When doing this, we’re seeing that some controls still don’t clear their internal DependencyProperties, which has forced us to use unpleasant reflection code to clear those values. Along with being annoying to maintain, it’s difficult to know for certain if we’ve found everything. Our hope is that you can show us a better way to solve this, or to integrate our fixes into your controls so other users can benefit and so we don’t need to maintain these.

The Specifics:

1. Editors

We use several editor controls in our editors, including:
• FontFamilyComboBox
• FontSizeComboBox
• ForeColorEditBox
• BackColorEditBox

When we close our project and look at what’s keeping our ProjectViewModel in memory (using the ANTS memory profiler), we see that the above controls continue to hold references to a child ViewModel of our project.

For the FontFamilyComboBox, the reference chain is as follows:
1. FontFamilyComboBox has a visual child that’s a Popup.
2. Within Popup, there’s a _popupRoot.Value expression. (note that _popupRoot is private)
3. The Value property is a DependencyObject and its DataContext property holds the ViewModel reference.

The other controls listed above have the same issue. Is there a more direct way to break this reference or a function we can call that will handle this for us?

2. Ribbon SplitButtons

For ribbon split buttons, the problem is nastier. It seems that every SplitButton we use has the same Popup problem as the aforementioned Editors. However, cleanup is nastier since the reference is held after switching tabs. Thus, we have to iterate over all the SplitButtons in all our tab groups to ensure no references are accidently held.

As a reference, I’ve included our cleanup logic below to help make our approach clear. Again, we’d prefer to not have to rely on reflection and repeated cleanup checks to free these unexpected references. Is there anything we can do?

Thanks,

-Craig
      public static void CleanupPopup(Visual popupParent)
        {
            var popup = GetVisualChild<Popup>(popupParent);
            CleanupPopup(popup);
        }

        public static void CleanupPopup(Popup popup)
        {
            if (popup != null)
            {
                FieldInfo popupRootFieldInfo = typeof(Popup).GetField("_popupRoot", BindingFlags.Instance | BindingFlags.NonPublic);
                Debug.Assert(popupRootFieldInfo != null, "The Popup's popupRoot field is missing.");

                if (popupRootFieldInfo != null)
                {
                    var popupRoot = popupRootFieldInfo.GetValue(popup);
                    if (popupRoot != null)
                    {
                        PropertyInfo valuePropertyInfo = popupRoot.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.NonPublic);
                        Debug.Assert(valuePropertyInfo != null, "The PopupRoot's Value property is missing.");

                        if (valuePropertyInfo != null)
                        {
                            var value = valuePropertyInfo.GetValue(popupRoot, null) as DependencyObject;
                            if (value != null)
                            {
                                value.SetValue(FrameworkElement.DataContextProperty, FrameworkElement.DataContextProperty.DefaultMetadata.DefaultValue);
                            }
                        }
                    }
                }
            }
        }

Comments (2)

Posted 4 years ago by Actipro Software Support - Cleveland, OH, USA
Hi Craig,

We haven't had any reports of issues like this. If you can put together a small sample project that reproduces the issues you describe, then we can take a closer look. Just email it to our support address and be sure to remove any executable files.

We may be doing another small release in the next few days to fix some small things, so if you can get this to us quickly we may be able to include any fixes in that release.

Actipro Software Support
Posted 4 years ago by Craig - Varigence, Inc.
I've just sent a mail to support@actiprosoftware with a sample project attached that reproduces the issue.

Thanks,

-Craig
Information The latest build of this product (2014.1 build 0602) was released 2 months ago, which was after the last post in this thread.

Add a Comment

Please log in to a validated account to post comments.