RibbonEditorStyleBehavior causes memory leak

Ribbon for WPF Forum

Posted 14 years ago by Jon Cain - Software Architect, AutoMon Corporation
Version: 10.1.0521
Platform: .NET 4.0
Environment: Windows 7 (64-bit)
Avatar
Using RibbonEditorsStyleBehavior.ApplyRibbonCompatibleStyles="True" causes a child window to remain in memory forever, i.e., it's never garbage collected.

Here is some sample code that demonstrates the problem:

Window1.xaml -> "Main Window"

<Window 
  x:Class="RibbonEditorMemoryLeak.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Window1" Height="300" Width="300">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Button Click="OpenChildWindow_Click">Open Child Window</Button>
    <Button Grid.Row="1" Click="GarbageCollect_Click">Garbage Collect</Button>
    <TextBlock Grid.Row="2" FontWeight="Bold">Watch Debug Output for messages.</TextBlock>
  </Grid>
</Window>
Window1.xaml.cs

using System;
using System.Diagnostics;
using System.Windows;

namespace RibbonEditorMemoryLeak
{
   public partial class Window1 : Window
   {
      public Window1()
      {
         InitializeComponent();
      }

      private void OpenChildWindow_Click(object sender, RoutedEventArgs e)
      {
         Debug.WriteLine("OpenChildWindow_Click() -> Opening Child Window");
         new RibbonWindow1().Show();
      }

      private void GarbageCollect_Click(object sender, RoutedEventArgs e)
      {
         Debug.WriteLine("GarbageCollect_Click()");
         GC.Collect();
         GC.WaitForPendingFinalizers();
         GC.Collect();
      }
   }
}
RibbonWindow1.xaml -> "Child Window"

<ribbon:RibbonWindow 
  x:Class="RibbonEditorMemoryLeak.RibbonWindow1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:shared="http://schemas.actiprosoftware.com/winfx/xaml/shared" 
    xmlns:ribbon="http://schemas.actiprosoftware.com/winfx/xaml/ribbon" 
  xmlns:ribboneditors="http://schemas.actiprosoftware.com/winfx/xaml/ribboneditors"
  ApplicationName="RibbonWindow1" Width="620" Height="420"
  ribboneditors:RibbonEditorsStyleBehavior.ApplyRibbonCompatibleStyles="True">
    <Grid>
    <TextBlock TextWrapping="WrapWithOverflow">
        This window will not get Garbage Collected because RibbonEditorsStyleBehavior.ApplyRibbonCompatibleStyles="True"
    </TextBlock>
  </Grid>
</ribbon:RibbonWindow>
RibbonWindow1.xaml.cs

using System.Diagnostics;

namespace RibbonEditorMemoryLeak
{

   public partial class RibbonWindow1 : ActiproSoftware.Windows.Controls.Ribbon.RibbonWindow
   {
      public RibbonWindow1()
      {
         InitializeComponent();
         Debug.WriteLine("RibbonWindow1() -> constructed");
      }

      ~RibbonWindow1()
      {
         Debug.WriteLine("~RibbonWindow1() -> deconstructed");
      }
   }
}

Comments (6)

Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Jon,

It looks like the WPF ResourceDictionary is maintaining a reference to the first instance of your child window. Really, it could be any object but is the first element that the ApplyRibbonCompatibleStyles to set to true on. If you open and close several child windows, only the first one is retained.

You could manually clear the ApplyRibbonCompatibleStyles property on the Window, like so:
public Window2() {
    InitializeComponent();
    this.Unloaded += new RoutedEventHandler(Window2_Unloaded);
}

void Window2_Unloaded(object sender, System.Windows.RoutedEventArgs e) {
    RibbonEditorsStyleBehavior.SetApplyRibbonCompatibleStyles(this, false);
}
Unfortunately, there's a bug in WPF that was fixed in .NET 4.0, that prevents this from working in .NET 3.5 SP1 or earlier. You can find more information on this here.

To get around this completely, for all versions of .NET, you can manually merge a new instance of the associated ResourceDictionary. Something like this would work the same as setting ApplyRibbonCompatibleStyles (which is just there for convenience), but doesn't reuse the same instance.
<ribbon:RibbonWindow.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/ActiproSoftware.Editors.Interop.Ribbon.Wpf351;component/Windows.Controls.Editors.Interop.Ribbon/RibbonEditorsResourceDictionary.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</ribbon:RibbonWindow.Resources>


Actipro Software Support

Posted 14 years ago by Jon Cain - Software Architect, AutoMon Corporation
Avatar
Do you know when there will be a 4.0 version of Actipro Studio?
Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Jon,

We target 3.5 sp1 and don't have any iummediate plans to target 4.0 because we need to support the older framework for a while for other customers.

Regardless, as long as your application is configured to target .NET 4.0, then our assemblies will run on that version also. And, the ResourceDictionary bug mentioned above with not be present in your application or our assemblies.


Actipro Software Support

Posted 14 years ago by Jon Cain - Software Architect, AutoMon Corporation
Avatar
Either it's not fixed in .NET 4.0 or there's a different problem because I still experience the problem when targeting the 4.0 framework.
Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Jon,

Just to be clear, I meant that reseting ApplyRibbonCompatibleStyles to false would only work in .NET 4.0.

So to use the ApplyRibbonCompatibleStyles with secondary windows (i.e. not a window that is open as long as the application is running), you would need to add the Unloaded event handler, reset the ApplyRibbonCompatibleStyles property to false in the handler, and target .NET 4.0.

If this is what your sample is doing, please send along your sample project (sans any executable files) and we can see what's different from our sample.


Actipro Software Support

Posted 14 years ago by Jon Cain - Software Architect, AutoMon Corporation
Avatar
I understand now. The workaround works. Thanks.
The latest build of this product (v24.1.1) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.