Index: src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeView.cs
===================================================================
diff -u -rf1713196b96f96ed637286a1d8c6236a133268ae -r2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb
--- src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeView.cs (.../TreeView.cs) (revision f1713196b96f96ed637286a1d8c6236a133268ae)
+++ src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeView.cs (.../TreeView.cs) (revision 2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb)
@@ -213,6 +213,16 @@
return controller.CanRenameNode(SelectedNode);
}
+ public void EnableDataEventListeners()
+ {
+ controller.EnableDataEventListeners();
+ }
+
+ public void DisableDataEventListeners()
+ {
+ controller.DisableDataEventListeners();
+ }
+
public void EnsureVisible(object item) { }
public ITreeNodePresenter GetTreeViewNodePresenter([NotNull] object nodeData, ITreeNode node)
@@ -401,6 +411,15 @@
controller.OnTreeViewHandleCreated();
}
+ protected override void OnHandleDestroyed(EventArgs e)
+ {
+ if (controller != null)
+ {
+ controller.OnTreeViewHandleDestroyed();
+ }
+ base.OnHandleDestroyed(e);
+ }
+
///
/// Custom drawing.
///
@@ -423,6 +442,8 @@
{
if (disposing && controller != null)
{
+ controller.OnTreeViewHandleDestroyed();
+ controller.Dispose();
controller = null;
}
@@ -711,7 +732,9 @@
if (node.IsOnCheckBox(point))
{
+ DisableDataEventListeners();
node.Checked = !node.Checked;
+ EnableDataEventListeners();
}
if (node.IsOnExpandButton(point))
Index: src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeViewController.cs
===================================================================
diff -u -r0f4f3090613131cc878aeff213dd14e7658e0a7b -r2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb
--- src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeViewController.cs (.../TreeViewController.cs) (revision 0f4f3090613131cc878aeff213dd14e7658e0a7b)
+++ src/Common/DelftTools.Controls.Swf/TreeViewControls/TreeViewController.cs (.../TreeViewController.cs) (revision 2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb)
@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using DelftTools.Utils.Collections;
using DelftTools.Utils.Collections.Generic;
using log4net;
+using Timer = System.Windows.Forms.Timer;
namespace DelftTools.Controls.Swf.TreeViewControls
{
- public class TreeViewController
+ public class TreeViewController : IDisposable
{
private static readonly ILog Log = LogManager.GetLogger(typeof(TreeViewController));
@@ -26,16 +28,37 @@
this.treeView = treeView;
nodePresenters.CollectionChanged += NodePresentersCollectionChanged;
+
+ // for a time being we use timer here to perform full refresh to avoid double refresh
+ fullRefreshTimer.Tick += (sender, args) =>
+ {
+ fullRefreshTimer.Stop();
+ treeView.Refresh();
+ };
}
+ // use timer in order to combine property and collection change
+ // note that timer is active only when there is a full refresh taking place
+ readonly Timer fullRefreshTimer = new Timer { Interval = 250 };
+
public void WaitUntilAllEventsAreProcessed()
{
- while (treeView.IsUpdateSuspended)
+ while (treeView.IsUpdateSuspended || (treeView.Visible && fullRefreshTimer.Enabled))
{
Application.DoEvents();
}
}
+ private void FullRefreshEventHandler(object sender, EventArgs eventArgs)
+ {
+ if (fullRefreshTimer.Enabled)
+ {
+ fullRefreshTimer.Stop(); // Reset timer when already started before
+ }
+
+ fullRefreshTimer.Start(); // schedule full refresh
+ }
+
///
/// List of registered node presenters
///
@@ -52,12 +75,18 @@
get { return data; }
set
{
+ if (data != null)
+ {
+ DisableDataEventListeners();
+ }
+
treeView.Nodes.Clear();
data = value;
if (data == null) return;
CreateRootNode();
+ EnableDataEventListeners();
treeView.SelectedNode = treeView.Nodes.Count > 0 ? treeView.Nodes[0] : null;
}
@@ -332,6 +361,36 @@
}, false);
}
+ internal void EnableDataEventListeners()
+ {
+ var notifyPropertyChanged = data as INotifyPropertyChanged;
+ if (notifyPropertyChanged != null)
+ {
+ (notifyPropertyChanged).PropertyChanged += DataPropertyChanged;
+ }
+
+ var notifyCollectionChange = data as INotifyCollectionChange;
+ if (notifyCollectionChange != null)
+ {
+ (notifyCollectionChange).CollectionChanged += DataCollectionChanged;
+ }
+ }
+
+ internal void DisableDataEventListeners()
+ {
+ var notifyPropertyChanged = data as INotifyPropertyChanged;
+ if (notifyPropertyChanged != null)
+ {
+ (notifyPropertyChanged).PropertyChanged -= DataPropertyChanged;
+ }
+
+ var notifyCollectionChange = data as INotifyCollectionChange;
+ if (notifyCollectionChange != null)
+ {
+ (notifyCollectionChange).CollectionChanged -= DataCollectionChanged;
+ }
+ }
+
private bool HasChildren(ITreeNode treeNode)
{
return GetChildNodeObjects(treeNode).Any();
@@ -353,6 +412,55 @@
return nodePresenterFunction(nodePresenter);
}
+ private void DataCollectionChanged(object sender, NotifyCollectionChangingEventArgs e)
+ {
+ if(SkipEvents)
+ {
+ return;
+ }
+
+ DataCollectionChangedSynchronized(sender, e);
+
+ FullRefreshEventHandler(sender, e);
+ }
+
+ private void DataCollectionChangedSynchronized(object sender, NotifyCollectionChangingEventArgs e)
+ {
+ var nodePresenter = ResolveNodePresenterForData(e.Item);
+ if (nodePresenter == null)
+ {
+ return;
+ }
+
+ nodePresenter.OnCollectionChanged(sender, e);
+ }
+
+ public static bool SkipEvents; // for debugging purposes, find a better way (see usage)
+
+ private void DataPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if(SkipEvents)
+ {
+ return;
+ }
+
+ var nodePresenter = ResolveNodePresenterForData(sender);
+
+ if (nodePresenter == null) return;
+ var node = treeView.GetNodeByTag(sender);
+
+ // HACK: bug in WaterFlowModel1DBoundaryDataNodeDataNodePresenter, in some cases event somes with a sender which is child of actual node.Tag object - find out how to fix it
+ var actualSender = sender;
+ if(node != null && sender != node.Tag)
+ {
+ actualSender = node.Tag;
+ }
+
+ nodePresenter.OnPropertyChanged(actualSender, node, e);
+
+ FullRefreshEventHandler(sender, e);
+ }
+
private void CreateRootNode()
{
var rootNode = new TreeNode(treeView) {Tag = data};
@@ -424,9 +532,23 @@
nodePresenter.OnDragDrop(nodeDragging.Tag, parentNode.Tag, nodeDropTarget.Tag, dragOperation, dropAtLocation);
}
+ #region Implementation of IDisposable
+
+ public void Dispose()
+ {
+ DisableDataEventListeners();
+ }
+
+ #endregion
+
public void OnTreeViewHandleCreated()
{
treeView.Refresh(); // Ensure the treeview is always up to date after creating handle (data is set and might be changed before enabling the delayed event handlers)
}
+
+ public void OnTreeViewHandleDestroyed()
+ {
+ fullRefreshTimer.Stop();
+ }
}
}
Index: src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectExplorer.cs
===================================================================
diff -u -rf1713196b96f96ed637286a1d8c6236a133268ae -r2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb
--- src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectExplorer.cs (.../ProjectExplorer.cs) (revision f1713196b96f96ed637286a1d8c6236a133268ae)
+++ src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectExplorer.cs (.../ProjectExplorer.cs) (revision 2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb)
@@ -106,5 +106,15 @@
public Image Image { get; set; }
public void EnsureVisible(object item) { }
public ViewInfo ViewInfo { get; set; }
+
+ public void EndWaitMode()
+ {
+ ProjectTreeView.EnableEvents();
+ }
+
+ public void BeginWaitMode()
+ {
+ ProjectTreeView.DisableEvents();
+ }
}
}
Index: src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectExplorerGuiPlugin.cs
===================================================================
diff -u -rf1713196b96f96ed637286a1d8c6236a133268ae -r2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb
--- src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectExplorerGuiPlugin.cs (.../ProjectExplorerGuiPlugin.cs) (revision f1713196b96f96ed637286a1d8c6236a133268ae)
+++ src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectExplorerGuiPlugin.cs (.../ProjectExplorerGuiPlugin.cs) (revision 2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb)
@@ -140,12 +140,12 @@
private void ApplicationProjectSaved(Project project)
{
-
+ projectExplorer.EndWaitMode();
}
private void ApplicationOnProjectSaving(Project project)
{
-
+ projectExplorer.BeginWaitMode();
}
private void ApplicationProjectClosed(Project project)
Index: src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectTreeView.cs
===================================================================
diff -u -rf1713196b96f96ed637286a1d8c6236a133268ae -r2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb
--- src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectTreeView.cs (.../ProjectTreeView.cs) (revision f1713196b96f96ed637286a1d8c6236a133268ae)
+++ src/DeltaShell/DeltaShell.Plugins.ProjectExplorer/ProjectTreeView.cs (.../ProjectTreeView.cs) (revision 2ace0d3a03d5bf9e372a9c1032f996488fe2c4eb)
@@ -299,6 +299,16 @@
treeView.StartLabelEdit();
}
+ public void EnableEvents()
+ {
+ treeView.EnableDataEventListeners();
+ }
+
+ public void DisableEvents()
+ {
+ treeView.DisableDataEventListeners(); // HACK: dangerous, all changes in the tree nodes during save won't be shown
+ }
+
private void buttonsPropertiesClick(object sender, EventArgs e)
{
gui.CommandHandler.ShowProperties();