How to properly deal with IDisposable UserControl on XAML page

1 day ago 3
ARTICLE AD BOX

I have a user control that I did not write. The control's XAML has an object that has unmanaged resources. It creates Direct3D render targets and depth stencil surfaces and the like, and holds DirectX and OpenGL resources acquired through interop. I believe these came from the OpenTK NuGet package.. Therefore the author of the control implemented IDisposable.

But since the control is on a XAML page and we don't control its lifetime, the author doesn't get an opportunity to call Dispose with anything like a using statement. Therefore the author decided to call Dispose in its Unloaded handler.

But that is the source of my problem. The view on which this control sits can get loaded and unloaded multiple times. I don't control its lifetime, WPF does and WPF likes to re-use it. So the Unloaded handler gets called, Dispose gets called which frees up the unmanaged resources and then the same instance gets loaded again.

From reading Should IDisposable.Dispose() be made safe to call multiple times? and plenty of other threads, I have always understood the following about implementing IDisposable:

You should always try to explicitly call it yourself

You should not be in the habit of calling it more than once

So what is the correct way to manage this? Should I ignore item #2 and try to create some sort of Initialize function to pair alongside Dispose that makes them safe to call over and over?

Or should I add a finalizer to this control that calls Dispose for me? I am not sure that's going to work as the unmanaged resources that are freed need (I think) to be freed on the same UI thread that allocated them.

Is there some other approach that is correct?

Here is a bit of the XAML of the control:

<UserControl x:Class="GelSight.Modules.Common.Controls.SurfaceControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d"> <Grid x:Name="Scene" > <ctrl:SurfaceWpfGlControl x:Name="Chart" HorizontalAlignment="{Binding ElementName=Root, Path=HorizontalContentAlignment}" VerticalAlignment="{Binding ElementName=Root, Path=VerticalContentAlignment}" OnRotationXChanged="OnChartRotationXChanged"

And here is the relevant code-behind. The item 'Chart' (declared in the XAML) is what needs to be disposed. It has unmanaged OpenGL resource going all the way down to a 3rd party control)

public partial class SurfaceControl : IDisposable { public SurfaceControl() { InitializeComponent(); Chart.Loaded += Chart_Loaded; Chart.Unloaded += Chart_Unloaded; } private async void Chart_Loaded(object sender, RoutedEventArgs e) { try { await Initialize3dControlAsync(); } catch (Exception ex) { Log.Error(ex); } } private void Chart_Unloaded(object sender, RoutedEventArgs e) { Chart.Dispose(); }
Read Entire Article