/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Diagnostics; namespace ElmSharp { /// /// Enumeration for the Tooltip orientation. /// /// preview public enum TooltipOrientation { /// /// Default value. Tooltip moves with a mouse pointer. /// None, /// /// Tooltip should appear to the top left of the parent. /// TopLeft, /// /// Tooltip should appear to the left of the parent. /// Top, /// /// Tooltip should appear to the top right of the parent. /// TopRight, /// /// Tooltip should appear to the left of the parent. /// Left, /// /// Tooltip should appear to the center of the parent. /// Center, /// /// Tooltip should appear to the right of the parent. /// Right, /// /// Tooltip should appear to the bottom left of the parent. /// BottomLeft, /// /// Tooltip should appear to the bottom of the parent. /// Bottom, /// /// Tooltip should appear to the bottom right of the parent. /// BottomRight, } /// /// Enumeration for the aspect control. /// /// preview public enum AspectControl { /// /// Preference on the scaling unset. /// None = 0, /// /// Same effect as the unset preference on the scaling. /// Neither = 1, /// /// Use all horizontal container space to place an object using the given aspect. /// Horizontal = 2, /// /// Use all vertical container space to place an object using the given aspect. /// Vertical = 3, /// /// Use all horizontal @b and vertical container spaces to place an object (never growing it out of those bounds), using the given aspect. /// Both = 4 } /// /// How the object should be rendered to output. /// /// 5 public enum RenderOp { /// /// default op: d = d * (1 - sa) + s /// Blend = 0, /// /// d = d*(1 - sa) + s*da /// BlendRel = 1, /// /// d = s /// Copy = 2, /// /// d = s*da /// CopyRel = 3, /// /// d = d + s /// Add = 4, /// /// d = d + s*da /// AddRel = 5, /// /// d = d - s /// Sub = 6, /// /// d = d - s*da /// SubRel = 7, /// /// d = d*s + d*(1 - sa) + s*(1 - da) /// Tint = 8, /// /// d = d*(1 - sa + s) /// TintRel = 9, /// /// d = d*sa /// Mask = 10, /// /// d = d*s /// Mul = 11 } /// /// The EvasObject is a base class for other widget classes. /// /// preview public abstract class EvasObject { private IntPtr _realHandle = IntPtr.Zero; private EvasCanvas _evasCanvas; private string _automationId; private event EventHandler _backButtonPressed; private event EventHandler _moreButtonPressed; private Interop.Eext.EextEventCallback _backButtonHandler; private Interop.Eext.EextEventCallback _moreButtonHandler; private static Dictionary s_handleTable = new Dictionary(); /// /// Sets or gets the handle for EvasObject. /// /// preview public IntPtr Handle { get; protected set; } /// /// Gets the parent object for EvasObject. /// /// preview public EvasObject Parent { get; private set; } /// /// Sets or gets the real handle for EvasObject. /// /// preview public IntPtr RealHandle { get { return _realHandle == IntPtr.Zero ? Handle : _realHandle; } protected set { _realHandle = value; Interop.Evas.evas_object_show(_realHandle); } } EvasObjectEvent _deleted; EvasObjectEvent _keyup; EvasObjectEvent _keydown; EvasObjectEvent _moved; EvasObjectEvent _resized; EvasObjectEvent _shown; EvasObjectEvent _hidden; EventHandler _renderPost; Interop.Evas.EvasCallback _renderPostCallback = null; Interop.Elementary.Elm_Tooltip_Content_Cb _tooltipContentCallback = null; GetTooltipContentDelegate _tooltipContentDelegate = null; readonly HashSet _eventStore = new HashSet(); /// /// Creates and initializes a new instance of the EvasObject class with the parent EvasObject class parameter. /// /// Parent EvasObject class. /// preview protected EvasObject(EvasObject parent) : this() { Debug.Assert(parent == null || parent.IsRealized); Realize(parent); } /// /// Creates and initializes a new instance of the EvasObject class. /// /// preview protected EvasObject() { _backButtonHandler = new Interop.Eext.EextEventCallback((d, o, i) => { _backButtonPressed?.Invoke(this, EventArgs.Empty); }); _moreButtonHandler = new Interop.Eext.EextEventCallback((d, o, i) => { _moreButtonPressed?.Invoke(this, EventArgs.Empty); }); OnInstantiated(); _tooltipContentCallback = (d, o, t) => { return _tooltipContentDelegate?.Invoke(); }; } // C# Finalizer was called on GC thread // So, We can't access to EFL object // And When Finalizer was called, Field can be already released. //~EvasObject() //{ // Unrealize(); //} /// /// Deleted will be triggered when the widght is deleted. /// /// preview public event EventHandler Deleted; /// /// KeyUp will be triggered when the key is loose. /// /// preview public event EventHandler KeyUp { add { _keyup.On += value; } remove { _keyup.On -= value; } } /// /// KeyDown will be triggered when the key is pressed down. /// /// preview public event EventHandler KeyDown { add { _keydown.On += value; } remove { _keydown.On -= value; } } /// /// BackButtonPressed will be triggered when the Back button is pressed. /// /// preview public event EventHandler BackButtonPressed { add { if (_backButtonPressed == null) { Interop.Eext.eext_object_event_callback_add(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_BACK, _backButtonHandler, IntPtr.Zero); } _backButtonPressed += value; } remove { _backButtonPressed -= value; if (_backButtonPressed == null) { Interop.Eext.eext_object_event_callback_del(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_BACK, _backButtonHandler); } } } /// /// MoreButtonPressed will be triggered when the More button is pressed. /// /// preview public event EventHandler MoreButtonPressed { add { if (_moreButtonPressed == null) { Interop.Eext.eext_object_event_callback_add(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_MORE, _moreButtonHandler, IntPtr.Zero); } _moreButtonPressed += value; } remove { _moreButtonPressed -= value; if (_moreButtonPressed == null) { Interop.Eext.eext_object_event_callback_del(RealHandle, Interop.Eext.EextCallbackType.EEXT_CALLBACK_MORE, _moreButtonHandler); } } } /// /// Moved will be triggered when the widght is moved. /// /// preview public event EventHandler Moved { add { _moved.On += value; } remove { _moved.On -= value; } } /// /// Resized Event Handler of the current widget's size. /// /// preview public event EventHandler Resized { add { _resized.On += value; } remove { _resized.On -= value; } } /// /// Shown will be triggered when the widget is shown. /// /// preview public event EventHandler Shown { add { _shown.On += value; } remove { _shown.On -= value; } } /// /// Hidden will be triggered when the widget is hidden. /// /// preview public event EventHandler Hidden { add { _hidden.On += value; } remove { _hidden.On -= value; } } /// /// RenderPost Event Handler of the current widget. /// /// preview public event EventHandler RenderPost { add { _renderPost += value; if (_renderPostCallback == null) { _renderPostCallback = new Interop.Evas.EvasCallback((o, e, d) => _renderPost?.Invoke(this, EventArgs.Empty)); Interop.Evas.evas_event_callback_add(Interop.Evas.evas_object_evas_get(RealHandle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback, IntPtr.Zero); } } remove { _renderPost -= value; if (_renderPost == null) { Interop.Evas.evas_event_callback_del(Interop.Evas.evas_object_evas_get(RealHandle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback); _renderPostCallback = null; } } } /// /// Called when a widget's tooltip is activated and needs content. /// /// /// preview public delegate EvasObject GetTooltipContentDelegate(); /// /// Gets a widget's status of realized or not. /// /// preview public bool IsRealized { get { return Handle != IntPtr.Zero; } } /// /// Gets EvasCanvas. /// /// preview public EvasCanvas EvasCanvas { get { if (_evasCanvas == null) _evasCanvas = new EvasCanvas(Handle); return _evasCanvas; } } /// /// Sets of gets a value that allow the automation framework to find and interact with this object. /// /// preview public string AutomationId { get { return _automationId; } set { if (_automationId != null) throw new InvalidOperationException("AutomationId may only be set one time."); _automationId = value; } } /// /// Gets the current class's Name. /// /// preview public string ClassName { get { return Interop.Eo.efl_class_name_get(Interop.Eo.efl_class_get(RealHandle)); } } /// /// Sets or gets the horizontal pointer hints for an object's weight. /// /// preview public double WeightX { get { return Interop.Evas.GetWeightX(Handle); } set { Interop.Evas.SetWeightX(Handle, value); } } /// /// Sets or gets the vertical pointer hints for an object's weight. /// /// preview public double WeightY { get { return Interop.Evas.GetWeightY(Handle); } set { Interop.Evas.SetWeightY(Handle, value); } } /// /// Sets or gets the horizontal alignment hint of an object's alignment. /// /// preview public virtual double AlignmentX { get { return Interop.Evas.GetAlignX(Handle); } set { Interop.Evas.SetAlignX(Handle, value); } } /// /// Sets or gets the vertical alignment hint of an object's alignment. /// /// preview public virtual double AlignmentY { get { return Interop.Evas.GetAlignY(Handle); } set { Interop.Evas.SetAlignY(Handle, value); } } /// /// Sets or gets the width hints for an object's minimum size. /// /// preview public int MinimumWidth { get { int w, h; Interop.Evas.evas_object_size_hint_min_get(RealHandle, out w, out h); return w; } set { int h = MinimumHeight; Interop.Evas.evas_object_size_hint_min_set(RealHandle, value, h); } } /// /// Sets or gets the height hints for an object's minimum size. /// /// preview public int MinimumHeight { get { int w, h; Interop.Evas.evas_object_size_hint_min_get(RealHandle, out w, out h); return h; } set { int w = MinimumWidth; Interop.Evas.evas_object_size_hint_min_set(RealHandle, w, value); } } /// /// Gets the visible state of the given Evas object. /// /// preview public bool IsVisible { get { return Interop.Evas.evas_object_visible_get(Handle); } } /// /// Sets or gets the position and (rectangular) size of the given Evas object. /// /// preview public Rect Geometry { get { int x, y, w, h; Interop.Evas.evas_object_geometry_get(Handle, out x, out y, out w, out h); Rect rect = new Rect(x, y, w, h); return rect; } set { Interop.Evas.evas_object_geometry_set(Handle, value.X, value.Y, value.Width, value.Height); } } /// /// Sets or gets the general or main color of the given Evas object. /// /// preview public virtual Color Color { get { int r, g, b, a; Interop.Evas.evas_object_color_get(RealHandle, out r, out g, out b, out a); return Color.FromRgba(r, g, b, a); } set { Interop.Evas.SetPremultipliedColor(RealHandle, value.R, value.G, value.B, value.A); } } /// /// Sets or gets the map enabled state. /// /// preview public bool IsMapEnabled { get { return Interop.Evas.evas_object_map_enable_get(Handle); } set { Interop.Evas.evas_object_map_enable_set(Handle, value); } } /// /// Sets or gets the current object's transformation map. /// /// preview public EvasMap EvasMap { get { IntPtr evasMap = Interop.Evas.evas_object_map_get(Handle); return new EvasMap(evasMap); } set { Interop.Evas.evas_object_map_set(Handle, value.Handle); } } /// /// Sets or gets whether an object is to repeat events. /// /// preview public bool RepeatEvents { get { var result = Interop.Evas.evas_object_repeat_events_get(Handle); Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_repeat_events_get(RealHandle)); return result; } set { if (Handle != RealHandle) { Interop.Evas.evas_object_repeat_events_set(RealHandle, value); } Interop.Evas.evas_object_repeat_events_set(Handle, value); } } /// /// Sets or gets whether events on a smart object's member should get propagated up to its parent. /// /// preview public bool PropagateEvents { get { var result = Interop.Evas.evas_object_propagate_events_get(Handle); Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_propagate_events_get(RealHandle)); return result; } set { if (Handle != RealHandle) { Interop.Evas.evas_object_propagate_events_set(RealHandle, value); } Interop.Evas.evas_object_propagate_events_set(Handle, value); } } /// /// Sets or gets whether an object is set to pass (ignore) events. /// /// preview public bool PassEvents { get { var result = Interop.Evas.evas_object_pass_events_get(Handle); Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_pass_events_get(RealHandle)); return result; } set { if (Handle != RealHandle) { Interop.Evas.evas_object_pass_events_set(RealHandle, value); } Interop.Evas.evas_object_pass_events_set(Handle, value); } } /// /// Sets or gets the style for this object tooltip. /// /// preview public string TooltipStyle { get { return Interop.Elementary.elm_object_tooltip_style_get(RealHandle); } set { Interop.Elementary.elm_object_tooltip_style_set(RealHandle, value); } } /// /// Sets or gets the orientation of tooltip. /// /// preview public TooltipOrientation TooltipOrientation { get { return (TooltipOrientation)Interop.Elementary.elm_object_tooltip_orient_get(RealHandle); } set { Interop.Elementary.elm_object_tooltip_orient_set(RealHandle, (int)value); } } /// /// Sets or gets size restriction state of an object's tooltip. /// /// preview public bool TooltipWindowMode { get { return Interop.Elementary.elm_object_tooltip_window_mode_get(RealHandle); } set { Interop.Elementary.elm_object_tooltip_window_mode_set(RealHandle, value); } } /// /// Sets the content to be shown in the tooltip object. /// /// preview public GetTooltipContentDelegate TooltipContentDelegate { get { return _tooltipContentDelegate; } set { _tooltipContentDelegate = value; if (value != null) { Interop.Elementary.elm_object_tooltip_content_cb_set(RealHandle, _tooltipContentCallback, IntPtr.Zero, null); } else { Interop.Elementary.elm_object_tooltip_content_cb_set(RealHandle, null, IntPtr.Zero, null); } } } /// /// Gets the movement freeze by 1. /// This gets the movement freeze count by one. /// /// preview public int TooltipMoveFreezeCount { get { return Interop.Elementary.elm_object_tooltip_move_freeze_get(RealHandle); } } /// /// Sets or gets whether an Evas object is to freeze (discard) events. /// /// preview public bool AllEventsFrozen { get { var result = Interop.Evas.evas_object_freeze_events_get(Handle); Debug.Assert(Handle == RealHandle || result == Interop.Evas.evas_object_freeze_events_get(RealHandle)); return result; } set { if (Handle != RealHandle) { Interop.Evas.evas_object_freeze_events_set(RealHandle, value); } Interop.Evas.evas_object_freeze_events_set(Handle, value); } } /// /// Sets or gets the layer of its canvas that the given object will be part of. /// /// preview public virtual int Layer { get { return Interop.Evas.evas_object_layer_get(Handle); } set { Interop.Evas.evas_object_layer_set(Handle, value); } } /// /// Sets or gets the render operation to be used for rendering the Evas object. /// /// 5 public RenderOp RenderOperation { get { return (RenderOp)Interop.Evas.evas_object_render_op_get(RealHandle); } set { Interop.Evas.evas_object_render_op_set(RealHandle, (Interop.Evas.RenderOp)value); } } /// /// Clips one object to another. /// /// The object to clip object by. /// preview public void SetClip(EvasObject clip) { Interop.Evas.evas_object_clip_set(Handle, clip); } /// /// Sets the hints for an object's alignment. /// /// The horizontal alignment hint as double value ranging from 0.0 to 1.0. The default alignment hint value is 0.5. /// The vertical alignment hint as double value ranging from 0.0 to 1.0. The default alignment hint value is 0.5. /// preview public void SetAlignment(double x, double y) { Interop.Evas.evas_object_size_hint_align_set(Handle, x, y); } /// /// Sets the hints for an object's weight. /// /// The non-negative double value to be used as horizontal weight hint. /// The non-negative double value to be used as vertical weight hint. /// preview public void SetWeight(double x, double y) { Interop.Evas.evas_object_size_hint_weight_set(Handle, x, y); } /// /// Sets the text for an object's tooltip. /// /// The text value to display inside the tooltip. /// preview public void SetTooltipText(string text) { Interop.Elementary.elm_object_tooltip_text_set(RealHandle, text); } /// /// Unsets an object's tooltip. /// /// preview public void UnsetTooltip() { Interop.Elementary.elm_object_tooltip_unset(RealHandle); } /// /// This increments the tooltip movement freeze count by one. /// If the count is more than 0, the tooltip position will be fixed. /// /// preview public void PushTooltipMoveFreeze() { Interop.Elementary.elm_object_tooltip_move_freeze_push(RealHandle); } /// /// This decrements the tooltip freeze count by one. /// /// preview public void PopTooltipMoveFreeze() { Interop.Elementary.elm_object_tooltip_move_freeze_pop(RealHandle); } /// /// Force hide the tooltip of the object. /// /// preview public void HideTooltip() { Interop.Elementary.elm_object_tooltip_hide(RealHandle); } /// /// Force show the tooltip of the object. /// /// preview public void ShowTooltip() { Interop.Elementary.elm_object_tooltip_show(RealHandle); } /// /// Makes the current object visible. /// /// preview public void Show() { Interop.Evas.evas_object_show(Handle); } /// /// Makes the current object invisible. /// /// preview public void Hide() { Interop.Evas.evas_object_hide(Handle); } /// /// Changes the size of the current object. /// /// The new width. /// The new height. /// preview public void Resize(int w, int h) { Interop.Evas.evas_object_resize(Handle, w, h); } /// /// Moves the current object to the given location. /// /// The X position to move the object. /// The Y position to move the object. /// preview public void Move(int x, int y) { Interop.Evas.evas_object_move(Handle, x, y); } /// /// Lowers the object to the bottom of its layer. /// /// preview public void Lower() { Interop.Evas.evas_object_lower(Handle); } /// /// Define the IntPtr operator. /// /// Parent object. /// preview public static implicit operator IntPtr(EvasObject obj) { if (obj == null) return IntPtr.Zero; return obj.Handle; } /// /// Define cast to EvasObject operator from IntPtr /// /// Native handle to EvasObject /// preview public static explicit operator EvasObject(IntPtr handle) => EvasObject.s_handleTable.TryGetValue(handle, out EvasObject obj) ? obj : null; /// /// Requests the keyname key events to be directed to the current object. /// /// The key to request events for. /// Set TRUE to request that the obj is the only object receiving the keyname events, otherwise set to FALSE. /// If the call succeeds then true, otherwise false. /// preview public bool KeyGrab(string keyname, bool exclusive) { return Interop.Evas.evas_object_key_grab(Handle, keyname, 0, 0, exclusive); } /// /// Removes the grab on the keyname key events. /// /// The key the grab is set for. /// preview public void KeyUngrab(string keyname) { Interop.Evas.evas_object_key_ungrab(Handle, keyname, 0, 0); } /// /// Marks the smart object as changed. /// /// preview public void MarkChanged() { Interop.Evas.evas_object_smart_changed(RealHandle); } /// /// Calls the calculate smart function immediately. /// This will force immediate calculations needed for renderization of this object. /// /// preview public void Calculate() { Interop.Evas.evas_object_smart_calculate(RealHandle); } /// /// Sets the hints for an object's aspect ratio. /// /// The policy or type of aspect ratio to apply to an object. /// The integer to be used as aspect width ratio term. /// The integer to be used as aspect height ratio term. /// preview public void SetSizeHintAspect(AspectControl aspect, int w, int h) { Interop.Evas.evas_object_size_hint_aspect_set(Handle, (int)aspect, w, h); } /// /// Gets the hints for an object's aspect ratio. /// /// The policy or type of aspect ratio to apply to an object. /// The integer to be used as aspect width ratio term. /// The integer to be used as aspect height ratio term. /// preview public void GetSizeHintAspect(out AspectControl aspect, out int w, out int h) { int aspectRatio; Interop.Evas.evas_object_size_hint_aspect_get(Handle, out aspectRatio, out w, out h); aspect = (AspectControl)aspectRatio; } /// /// Stacks immediately below anchor. /// /// The object below which to stack. /// preview public void StackBelow(EvasObject anchor) { Interop.Evas.evas_object_stack_below(Handle, anchor); } /// /// Stacks immediately above anchor. /// /// The object above which to stack. /// preview public void StackAbove(EvasObject anchor) { Interop.Evas.evas_object_stack_above(Handle, anchor); } /// /// Raises to the top of its layer. /// /// preview public void RaiseTop() { Interop.Evas.evas_object_raise(Handle); } /// /// Gets the geometry of a line number. /// /// The line number. /// x coordinate of the line. /// y coordinate of the line. /// w coordinate of the line. /// h coordinate of the line. /// True on success, or False on error. /// preview [Obsolete("GetTextBlockGeometryByLineNumber is obsolete as of version 5.0.0.14299 and is no longer supported.")] public bool GetTextBlockGeometryByLineNumber(int lineNumber, out int x, out int y, out int w, out int h) { x = -1; y = -1; w = -1; h = -1; IntPtr _edjeHandle = Interop.Elementary.elm_layout_edje_get(RealHandle); if (_edjeHandle == IntPtr.Zero) { return false; } IntPtr _textblock = Interop.Elementary.edje_object_part_object_get(_edjeHandle, "elm.text"); if (_textblock == IntPtr.Zero) { return false; } return Interop.Evas.evas_object_textblock_line_number_geometry_get(_textblock, lineNumber, out x, out y, out w, out h); } internal IntPtr GetData(string key) { return Interop.Evas.evas_object_data_get(RealHandle, key); } internal void SetData(string key, IntPtr data) { Interop.Evas.evas_object_data_set(RealHandle, key, data); } internal IntPtr DeleteData(string key) { return Interop.Evas.evas_object_data_del(RealHandle, key); } /// /// The callback of the Invalidate Event. /// /// preview protected virtual void OnInvalidate() { } /// /// The callback of the Instantiated Event. /// /// preview protected virtual void OnInstantiated() { } /// /// The callback of the Realized Event. /// /// preview protected virtual void OnRealized() { } /// /// The callback of the Unrealize Event. /// /// preview protected virtual void OnUnrealize() { } /// /// Creates a widget handle. /// /// Parent EvasObject. /// Handle IntPtr. /// preview protected abstract IntPtr CreateHandle(EvasObject parent); /// /// For this object bind Parent object.Init handle and all kinds of EvasObjectEvent. /// /// Parent object. /// preview public void Realize(EvasObject parent) { if (!IsRealized) { Parent = parent; Handle = CreateHandle(parent); Debug.Assert(Handle != IntPtr.Zero); s_handleTable[Handle] = this; (parent as Window)?.AddChild(this); OnRealized(); _deleted = new EvasObjectEvent(this, EvasObjectCallbackType.Del); _keydown = new EvasObjectEvent(this, RealHandle, EvasObjectCallbackType.KeyDown, EvasKeyEventArgs.Create); _keyup = new EvasObjectEvent(this, RealHandle, EvasObjectCallbackType.KeyUp, EvasKeyEventArgs.Create); _moved = new EvasObjectEvent(this, EvasObjectCallbackType.Move); _resized = new EvasObjectEvent(this, EvasObjectCallbackType.Resize); _shown = new EvasObjectEvent(this, EvasObjectCallbackType.Show); _hidden = new EvasObjectEvent(this, EvasObjectCallbackType.Hide); _deleted.On += (s, e) => MakeInvalidate(); _shown.On += (s, e) => Elementary.SendEvasObjectRealized(this); } } /// /// Removes the current object relationship with others. /// /// preview public void Unrealize() { if (IsRealized) { if (_renderPostCallback != null) { Interop.Evas.evas_event_callback_del(Interop.Evas.evas_object_evas_get(Handle), Interop.Evas.ObjectCallbackType.RenderPost, _renderPostCallback); _renderPostCallback = null; } OnUnrealize(); IntPtr toBeDeleted = Handle; Handle = IntPtr.Zero; DisposeEvent(); (Parent as Window)?.RemoveChild(this); Interop.Evas.evas_object_del(toBeDeleted); Deleted?.Invoke(this, EventArgs.Empty); Parent = null; s_handleTable.Remove(toBeDeleted); } } private void MakeInvalidate() { Deleted?.Invoke(this, EventArgs.Empty); OnInvalidate(); IntPtr toBeDeleted = Handle; Handle = IntPtr.Zero; MakeInvalidateEvent(); (Parent as Window)?.RemoveChild(this); Parent = null; _deleted = null; s_handleTable.Remove(toBeDeleted); } private void DisposeEvent() { var events = new List(_eventStore); foreach (var evt in events) { evt.Dispose(); } _eventStore.Clear(); } private void MakeInvalidateEvent() { foreach (var evt in _eventStore) { evt.MakeInvalidate(); } _eventStore.Clear(); } internal void AddToEventLifeTracker(IInvalidatable item) { _eventStore.Add(item); } internal void RemoveFromEventLifeTracker(IInvalidatable item) { _eventStore.Remove(item); } } }