From 6cbe9f9d2a604cdbb74f46f3710ea3dc60a87e55 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Sun, 27 Aug 2017 06:51:36 +0200 Subject: [PATCH] first step in implementing a dispose mechanism for graphic objects --- src/CompilerServices/CompilerServices.cs | 2 + src/CrowThread.cs | 2 + src/GraphicObjects/GraphicObject.cs | 71 +++++++++++++++++++++++- src/GraphicObjects/Group.cs | 14 ++++- src/GraphicObjects/PrivateContainer.cs | 9 ++- src/GraphicObjects/TemplatedControl.cs | 6 ++ src/GraphicObjects/TemplatedGroup.cs | 12 +++- src/Interface.cs | 51 +++++++++-------- 8 files changed, 135 insertions(+), 32 deletions(-) diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 5884ee66..5409aa5e 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -632,7 +632,9 @@ namespace Crow Type t = instance.GetType (); FieldInfo fiEvt = getEventHandlerField (t, eventName); if (fiEvt == null) { + #if DEBUG_BINDING Debug.WriteLine ("RemoveHandlerByName: Event '" + eventName + "' not found in " + instance); + #endif return; } EventInfo eiEvt = t.GetEvent (eventName); diff --git a/src/CrowThread.cs b/src/CrowThread.cs index 857ec1a3..fbcdc956 100644 --- a/src/CrowThread.cs +++ b/src/CrowThread.cs @@ -33,6 +33,7 @@ namespace Crow /// Thread monitored by current interface with Finished event when state==Stopped /// public class CrowThread { + public bool cancel = false; Thread thread; public event EventHandler Finished; public GraphicObject Host; @@ -53,6 +54,7 @@ namespace Crow public void Start() { thread.Start();} public void Cancel(){ if (thread.IsAlive){ + cancel = true; //cancelLoading = true; thread.Join (); //cancelLoading = false; diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index aad6e327..8fd9a6e9 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -38,8 +38,27 @@ using System.IO; namespace Crow { - public class GraphicObject : ILayoutable, IValueChange + public class GraphicObject : ILayoutable, IValueChange, IDisposable { + #region IDisposable implementation + + public virtual void Dispose () + { + #if DEBUG_DISPOSE + Debug.WriteLine ("{0} Disposed", this.ToString()); + #endif + + parent = null; + if (IsQueueForRedraw) + Debugger.Break (); + if (!localDataSourceIsNull) + DataSource = null; + Clipping?.Dispose (); + bmp?.Dispose (); + } + + #endregion + internal static ulong currentUid = 0; internal ulong uid = 0; @@ -804,12 +823,27 @@ namespace Crow public virtual bool Contains(GraphicObject goToFind){ return false; } + /// + /// return true if this is contained inside go + /// + public bool IsInside(GraphicObject go){ + ILayoutable p = this.Parent; + while (p != null) { + if (p == go) + return true; + p = p.Parent; + } + return false; + } #region Queuing /// /// Register old and new slot for clipping /// public virtual void ClippingRegistration(){ + #if DEBUG_UPDATE + Debug.WriteLine (string.Format("ClippingRegistration -> {0}", this.ToString ())); + #endif IsQueueForRedraw = false; if (Parent == null) return; @@ -821,6 +855,9 @@ namespace Crow /// /// Clip rectangle public virtual void RegisterClip(Rectangle clip){ + #if DEBUG_UPDATE + Debug.WriteLine (string.Format("RegisterClip -> {1}:{0}", clip, this.ToString ())); + #endif Rectangle r = clip + ClientRectangle.Position; if (CacheEnabled && !IsDirty) Clipping.UnionRectangle (r); @@ -835,6 +872,9 @@ namespace Crow [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterForGraphicUpdate () { + #if DEBUG_UPDATE + Debug.WriteLine (string.Format("RegisterForGraphicUpdate -> {0}", this.ToString ())); + #endif IsDirty = true; if (Width.IsFit || Height.IsFit) RegisterForLayouting (LayoutingType.Sizing); @@ -845,6 +885,9 @@ namespace Crow [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterForRedraw () { + #if DEBUG_UPDATE + Debug.WriteLine (string.Format("RegisterForRedraw -> {0}", this.ToString ())); + #endif IsDirty = true; if (RegisteredLayoutings == LayoutingType.None) currentInterface.EnqueueForRepaint (this); @@ -1091,6 +1134,9 @@ namespace Crow /// this trigger the effective drawing routine protected virtual void RecreateCache () { + #if DEBUG_UPDATE + Debug.WriteLine ("RecreateCache -> {0}", this.ToString ()); + #endif IsDirty = false; if (bmp != null) bmp.Dispose (); @@ -1102,6 +1148,9 @@ namespace Crow bmp.Flush (); } protected virtual void UpdateCache(Context ctx){ + #if DEBUG_UPDATE + Debug.WriteLine ("UpdateCache -> {0}", this.ToString ()); + #endif Rectangle rb = Slot + Parent.ClientRectangle.Position; if (clearBackground) { ctx.Save (); @@ -1119,6 +1168,9 @@ namespace Crow /// of the widget public virtual void Paint (ref Context ctx) { + #if DEBUG_UPDATE + Debug.WriteLine (string.Format("Paint -> {0}", this.ToString ())); + #endif //TODO:this test should not be necessary if (Slot.Height < 0 || Slot.Width < 0 || parent == null) return; @@ -1307,7 +1359,22 @@ namespace Crow protected virtual void onLogicalParentChanged(object sender, DataSourceChangeEventArgs e) { LogicalParentChanged.Raise (this, e); } - + internal void ClearTemplateBinding(){ + #if DEBUG_UPDATE + Debug.WriteLine (string.Format("ClearTemplateBinding: {0}", this.ToString())); + #endif + if (ValueChanged == null) + return; + EventInfo eiEvt = this.GetType().GetEvent ("ValueChanged"); + foreach (Delegate d in ValueChanged.GetInvocationList()) { + if (d.Method.Name == "dyn_tmpValueChanged") { + eiEvt.RemoveEventHandler (this, d); + #if DEBUG_BINDING + Debug.WriteLine ("\t{0} template binding handler removed in {1} for: {2}", d.Method.Name, this, "ValueChanged"); + #endif + } + } + } public override string ToString () { string tmp =""; diff --git a/src/GraphicObjects/Group.cs b/src/GraphicObjects/Group.cs index a02b9669..f3026290 100644 --- a/src/GraphicObjects/Group.cs +++ b/src/GraphicObjects/Group.cs @@ -73,16 +73,17 @@ namespace Crow public virtual void RemoveChild(GraphicObject child) { child.LayoutChanged -= OnChildLayoutChanges; - //child.Parent = null; + child.Parent = null; //check if HoverWidget is removed from Tree if (currentInterface.HoverWidget != null) { - if (this.Contains (currentInterface.HoverWidget)) + if (currentInterface.HoverWidget.IsInside(this)) currentInterface.HoverWidget = null; } lock (children) Children.Remove(child); + child.Dispose (); if (child == largestChild && Width == Measure.Fit) searchLargestChild (); @@ -97,8 +98,8 @@ namespace Crow while (Children.Count > 0) { GraphicObject g = Children [Children.Count - 1]; g.LayoutChanged -= OnChildLayoutChanges; - g.Parent = null; Children.RemoveAt (Children.Count - 1); + g.Dispose (); } } @@ -364,5 +365,12 @@ namespace Crow base.checkHoverWidget (e); } #endregion + + public override void Dispose () + { + foreach (GraphicObject c in children) + c.Dispose (); + base.Dispose (); + } } } diff --git a/src/GraphicObjects/PrivateContainer.cs b/src/GraphicObjects/PrivateContainer.cs index 499f998f..89b30753 100644 --- a/src/GraphicObjects/PrivateContainer.cs +++ b/src/GraphicObjects/PrivateContainer.cs @@ -55,11 +55,12 @@ namespace Crow if (child != null) { //check if HoverWidget is removed from Tree if (currentInterface.HoverWidget != null) { - if (this.Contains (currentInterface.HoverWidget)) + if (currentInterface.HoverWidget.IsInside(this)) currentInterface.HoverWidget = null; } contentSize = new Size (0, 0); child.LayoutChanged -= OnChildLayoutChanges; + child.Dispose (); child.Parent = null; this.RegisterForGraphicUpdate (); } @@ -212,6 +213,12 @@ namespace Crow } #endregion + public override void Dispose () + { + if (child != null) + child.Dispose (); + base.Dispose (); + } } } diff --git a/src/GraphicObjects/TemplatedControl.cs b/src/GraphicObjects/TemplatedControl.cs index b0d752ed..ba580dae 100644 --- a/src/GraphicObjects/TemplatedControl.cs +++ b/src/GraphicObjects/TemplatedControl.cs @@ -48,6 +48,9 @@ namespace Crow string _template; string caption; + /// + /// Template path + /// [XmlAttributeAttribute][DefaultValue(null)] public string Template { get { return _template; } @@ -99,6 +102,9 @@ namespace Crow protected virtual void loadTemplate(GraphicObject template = null) { + if (this.child != null)//template change, bindings has to be reset + this.ClearTemplateBinding(); + if (template == null) { if (!Interface.DefaultTemplates.ContainsKey (this.GetType ().FullName)) throw new Exception (string.Format ("No default template found for '{0}'", this.GetType ().FullName)); diff --git a/src/GraphicObjects/TemplatedGroup.cs b/src/GraphicObjects/TemplatedGroup.cs index 4e997598..e4e29404 100644 --- a/src/GraphicObjects/TemplatedGroup.cs +++ b/src/GraphicObjects/TemplatedGroup.cs @@ -56,7 +56,6 @@ namespace Crow int itemPerPage = 50; CrowThread loadingThread = null; - volatile bool cancelLoading = false; bool isPaged = false; @@ -274,7 +273,7 @@ namespace Crow ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate); for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) { - if (cancelLoading) + if ((bool)loadingThread?.cancel) return; loadPage (i); Thread.Sleep (1); @@ -316,7 +315,7 @@ namespace Crow for (int i = (pageNum - 1) * itemPerPage; i < pageNum * itemPerPage; i++) { if (i >= data.Count) break; - if (cancelLoading) + if ((bool)loadingThread?.cancel) return; loadItem (i, page); @@ -426,5 +425,12 @@ namespace Crow internal virtual void itemClick(object sender, MouseButtonEventArgs e){ SelectedIndex = data.IndexOf((sender as GraphicObject).DataSource); } + + public override void Dispose () + { + if (loadingThread != null) + loadingThread.Cancel (); + base.Dispose (); + } } } diff --git a/src/Interface.cs b/src/Interface.cs index adcb2830..baa46667 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -593,15 +593,40 @@ namespace Crow public void DeleteWidget(GraphicObject g) { if (_hoverWidget != null) { - if (g.Contains (_hoverWidget)) + if (_hoverWidget.IsInside(g)) HoverWidget = null; } lock (UpdateMutex) { - g.DataSource = null; - g.Visible = false; + RegisterClip (g.ScreenCoordinates (g.LastPaintedSlot)); GraphicTree.Remove (g); + g.Parent = null; + g.Dispose (); } } + /// Remove all Graphic objects from top container + public void ClearInterface() + { + lock (UpdateMutex) { + while (GraphicTree.Count > 0) { + //TODO:parent is not reset to null because object will be added + //to ObjectToRedraw list, and without parent, it fails + GraphicObject g = GraphicTree [0]; + if (_hoverWidget != null) { + if (_hoverWidget.IsInside(g)) + HoverWidget = null; + } + RegisterClip (g.ScreenCoordinates (g.LastPaintedSlot)); + GraphicTree.RemoveAt (0); + g.Dispose (); + } + } + #if DEBUG_LAYOUTING + LQIsTries = new List(); + curLQIsTries = new LQIList(); + LQIs = new List(); + curLQIs = new LQIList(); + #endif + } /// Put widget on top of other root widgets public void PutOnTop(GraphicObject g, bool isOverlay = false) { @@ -626,26 +651,6 @@ namespace Crow EnqueueForRepaint (g); } } - /// Remove all Graphic objects from top container - public void ClearInterface() - { - lock (UpdateMutex) { - while (GraphicTree.Count > 0) { - //TODO:parent is not reset to null because object will be added - //to ObjectToRedraw list, and without parent, it fails - GraphicObject g = GraphicTree [0]; - g.DataSource = null; - g.Visible = false; - GraphicTree.RemoveAt (0); - } - } - #if DEBUG_LAYOUTING - LQIsTries = new List(); - curLQIsTries = new LQIList(); - LQIs = new List(); - curLQIs = new LQIList(); - #endif - } /// Search a Graphic object in the tree named 'nameToFind' public GraphicObject FindByName (string nameToFind) -- 2.47.3