Skip to content

Commit 2fcdf95

Browse files
authored
Merge pull request #219 from miroiu/fix/218-memory-leak
Fix memory leak caused by auto panning timer
2 parents 9f68647 + 6c1e40b commit 2fcdf95

File tree

7 files changed

+71
-35
lines changed

7 files changed

+71
-35
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
> - Added AsRef extension method to InputGesture to convert it to an InputGestureRef
88
> - Bugfixes:
99
> - Fixed an issue where the gesture used for EditorGestures.Editor.SelectAll extracted from the ApplicationCommands was assumed to be a KeyGesture
10-
> - Fixed overrides of DrawDefaultArrowhead and DrawDirectionalArrowheadGeometry virtual methods not working in subclasses of the built in connections
10+
> - Fixed overrides of DrawDirectionalArrowheadGeometry virtual method not working in subclasses of the built in connections
11+
> - Fixed a memory leak caused by the auto panning timer
1112
1213
#### **Version 7.0.3**
1314

Examples/Nodify.Calculator/EditorView.xaml.cs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,57 @@
1-
using System.Windows;
1+
using Nodify.Interactivity;
2+
using System.Windows;
23
using System.Windows.Controls;
34
using System.Windows.Input;
45

56
namespace Nodify.Calculator
67
{
7-
public partial class EditorView : UserControl
8+
public class OperationsMenuHandler : InputElementState<NodifyEditor>
89
{
9-
public EditorView()
10-
{
11-
InitializeComponent();
10+
private static InputGesture OpenGesture { get; } = new Interactivity.MouseGesture(MouseAction.RightClick);
11+
private static InputGesture CloseGesture { get; } = new Interactivity.MouseGesture(MouseAction.LeftClick);
12+
13+
private OperationsMenuViewModel ViewModel => ((CalculatorViewModel)Element.DataContext).OperationsMenu;
1214

13-
EventManager.RegisterClassHandler(typeof(NodifyEditor), MouseLeftButtonDownEvent, new MouseButtonEventHandler(CloseOperationsMenu), true);
14-
EventManager.RegisterClassHandler(typeof(NodifyEditor), MouseRightButtonUpEvent, new MouseButtonEventHandler(OpenOperationsMenu));
15+
public OperationsMenuHandler(NodifyEditor element) : base(element)
16+
{
1517
}
1618

17-
private void OpenOperationsMenu(object sender, MouseButtonEventArgs e)
19+
protected override void OnMouseUp(MouseButtonEventArgs e)
1820
{
19-
if (e.OriginalSource is NodifyEditor editor && editor.DataContext is CalculatorViewModel calculator)
21+
if (OpenGesture.Matches(e.Source, e))
2022
{
21-
e.Handled = true;
22-
calculator.OperationsMenu.OpenAt(editor.MouseLocation);
23+
ViewModel.OpenAt(Element.MouseLocation);
2324
}
2425
}
2526

26-
private void CloseOperationsMenu(object sender, MouseButtonEventArgs e)
27+
protected override void OnMouseDown(MouseButtonEventArgs e)
2728
{
28-
ItemContainer? itemContainer = sender as ItemContainer;
29-
NodifyEditor? editor = sender as NodifyEditor ?? itemContainer?.Editor;
30-
31-
if (editor?.DataContext is CalculatorViewModel calculator)
29+
if (CloseGesture.Matches(e.Source, e))
3230
{
33-
calculator.OperationsMenu.Close();
31+
ViewModel.Close();
3432
}
3533
}
34+
}
35+
36+
public partial class EditorView : UserControl
37+
{
38+
public EditorView()
39+
{
40+
InitializeComponent();
41+
}
42+
43+
static EditorView()
44+
{
45+
InputProcessor.Shared<NodifyEditor>.RegisterHandlerFactory(editor => new OperationsMenuHandler(editor));
46+
47+
// Ensure the selecting handler is executed after the OperationsMenuHandler, otherwise left click events will not be received.
48+
InputProcessor.Shared<NodifyEditor>.RemoveHandlerFactory<EditorState.Selecting>();
49+
InputProcessor.Shared<NodifyEditor>.RegisterHandlerFactory(editor => new EditorState.Selecting(editor));
50+
}
3651

3752
private void OnDropNode(object sender, DragEventArgs e)
3853
{
39-
if(e.Source is NodifyEditor editor && editor.DataContext is CalculatorViewModel calculator
54+
if (e.Source is NodifyEditor editor && editor.DataContext is CalculatorViewModel calculator
4055
&& e.Data.GetData(typeof(OperationInfoViewModel)) is OperationInfoViewModel operation)
4156
{
4257
OperationViewModel op = OperationFactory.GetOperation(operation);
@@ -49,8 +64,8 @@ private void OnDropNode(object sender, DragEventArgs e)
4964

5065
private void OnNodeDrag(object sender, MouseEventArgs e)
5166
{
52-
if(e.LeftButton == MouseButtonState.Pressed && ((FrameworkElement)sender).DataContext is OperationInfoViewModel operation)
53-
{
67+
if (e.LeftButton == MouseButtonState.Pressed && ((FrameworkElement)sender).DataContext is OperationInfoViewModel operation)
68+
{
5469
var data = new DataObject(typeof(OperationInfoViewModel), operation);
5570
DragDrop.DoDragDrop(this, data, DragDropEffects.Copy);
5671
}

Nodify/Connections/LineConnection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ protected override void DrawDefaultArrowhead(StreamGeometryContext context, Poin
6868
}
6969
else
7070
{
71-
DrawDefaultArrowhead(context, source, target, arrowDirection, orientation);
71+
base.DrawDefaultArrowhead(context, source, target, arrowDirection, orientation);
7272
}
7373
}
7474

Nodify/Connectors/Connector.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ static Connector()
172172
public Connector()
173173
{
174174
InputProcessor.AddSharedHandlers(this);
175+
176+
Loaded += OnConnectorLoaded;
177+
Unloaded += OnConnectorUnloaded;
175178
}
176179

177180
/// <inheritdoc />
@@ -181,9 +184,6 @@ public override void OnApplyTemplate()
181184

182185
Container = this.GetParentOfType<ItemContainer>();
183186
Editor = Container?.Editor ?? this.GetParentOfType<NodifyEditor>();
184-
185-
Loaded += OnConnectorLoaded;
186-
Unloaded += OnConnectorUnloaded;
187187
}
188188

189189
#region Update Anchor

Nodify/Connectors/PendingConnection.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,13 @@ public override void OnApplyTemplate()
248248
{
249249
base.OnApplyTemplate();
250250

251+
if(Editor != null)
252+
{
253+
Editor.RemoveHandler(Connector.PendingConnectionStartedEvent, new PendingConnectionEventHandler(OnPendingConnectionStarted));
254+
Editor.RemoveHandler(Connector.PendingConnectionDragEvent, new PendingConnectionEventHandler(OnPendingConnectionDrag));
255+
Editor.RemoveHandler(Connector.PendingConnectionCompletedEvent, new PendingConnectionEventHandler(OnPendingConnectionCompleted));
256+
}
257+
251258
Editor = this.GetParentOfType<NodifyEditor>();
252259

253260
if (Editor != null)

Nodify/Editor/NodifyEditor.Panning.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -203,19 +203,25 @@ private void HandleAutoPanning(object? sender, EventArgs e)
203203
/// <param name="shouldDisable">Whether to enable or disable auto panning.</param>
204204
private void OnDisableAutoPanningChanged(bool shouldDisable)
205205
{
206-
if (shouldDisable)
206+
ClearTimer();
207+
if (!shouldDisable)
207208
{
208-
_autoPanningTimer?.Stop();
209-
}
210-
else if (_autoPanningTimer == null)
211-
{
212-
_autoPanningTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(AutoPanningTickRate),
213-
DispatcherPriority.Background, HandleAutoPanning, Dispatcher);
209+
_autoPanningTimer = new DispatcherTimer(DispatcherPriority.Background, Dispatcher)
210+
{
211+
Interval = TimeSpan.FromMilliseconds(AutoPanningTickRate)
212+
};
213+
_autoPanningTimer.Tick += HandleAutoPanning;
214+
_autoPanningTimer.Start();
214215
}
215-
else
216+
217+
void ClearTimer()
216218
{
217-
_autoPanningTimer.Interval = TimeSpan.FromMilliseconds(AutoPanningTickRate);
218-
_autoPanningTimer.Start();
219+
if (_autoPanningTimer != null)
220+
{
221+
_autoPanningTimer.Stop();
222+
_autoPanningTimer.Tick -= HandleAutoPanning;
223+
_autoPanningTimer = null;
224+
}
219225
}
220226
}
221227

Nodify/Editor/NodifyEditor.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ public NodifyEditor()
573573
SetValue(ViewportTransformPropertyKey, transform);
574574

575575
InputProcessor.AddSharedHandlers(this);
576+
577+
Unloaded += OnEditorUnloaded;
576578
}
577579

578580
/// <inheritdoc />
@@ -586,6 +588,11 @@ public override void OnApplyTemplate()
586588
OnDisableAutoPanningChanged(DisableAutoPanning);
587589
}
588590

591+
private void OnEditorUnloaded(object sender, RoutedEventArgs e)
592+
{
593+
OnDisableAutoPanningChanged(true);
594+
}
595+
589596
/// <inheritdoc />
590597
protected override DependencyObject GetContainerForItemOverride()
591598
=> new ItemContainer(this)

0 commit comments

Comments
 (0)