using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using Tango.Core.EventArguments; public static class FrameworkElementExtensions { #region Mouse Or Touch Events /// /// Registers for mouse or touch down. /// /// The element. /// The relative to. /// The handler. public static void RegisterForMouseOrTouchDown(this FrameworkElement element, FrameworkElement relativeTo, EventHandler handler) { bool mousePressed = false; bool touchDown = false; MouseButtonEventHandler mouseDownHandler = (x, e) => { if (!touchDown) { mousePressed = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = e.GetPosition }; handler(element, args); e.Handled = args.Handled; } else { touchDown = false; } }; //element.MouseDown += mouseDownHandler; element.AddHandler(FrameworkElement.MouseDownEvent, mouseDownHandler); EventHandler touchDownHandler = (x, e) => { if (!mousePressed) { touchDown = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.X, e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = (s) => { return e.GetTouchPoint(s).Position; }, TouchDevice = e.TouchDevice, }; handler(element, args); e.Handled = args.Handled; } else { touchDown = false; } }; //element.TouchDown += touchDownHandler; element.AddHandler(FrameworkElement.TouchDownEvent, touchDownHandler); MouseButtonEventHandler mouseUpHandler = (_, __) => { touchDown = false; mousePressed = false; }; //element.MouseUp += mouseUpHandler; element.AddHandler(FrameworkElement.MouseUpEvent, mouseUpHandler); //element.TouchDown += (_, __) => //{ //}; } /// /// Registers for mouse or touch down. /// /// The element. /// The handler. public static void RegisterForMouseOrTouchDown(this FrameworkElement element, EventHandler handler) { RegisterForMouseOrTouchDown(element, null, handler); } /// /// Registers for mouse or touch up. /// /// The element. /// The relative to. /// The handler. public static void RegisterForMouseOrTouchUp(this FrameworkElement element, FrameworkElement relativeTo, EventHandler handler) { bool mouseReleased = false; bool touchReleased = false; MouseButtonEventHandler mouseUpHandler = (x, e) => { if (!touchReleased) { mouseReleased = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = e.GetPosition }; handler(element, args); e.Handled = args.Handled; } else { touchReleased = false; } }; //element.MouseUp += mouseUpHandler; element.AddHandler(FrameworkElement.MouseUpEvent, mouseUpHandler); EventHandler touchUpHandler = (x, e) => { if (!mouseReleased) { touchReleased = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.X, e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = (s) => { return e.GetTouchPoint(s).Position; }, TouchDevice = e.TouchDevice, }; handler(element, args); e.Handled = args.Handled; } else { touchReleased = false; } }; //element.TouchUp += touchUpHandler; element.AddHandler(FrameworkElement.TouchUpEvent, touchUpHandler); EventHandler touchDownHandler = (_, __) => { touchReleased = false; mouseReleased = false; }; //element.TouchDown += touchDownHandler; element.AddHandler(FrameworkElement.TouchDownEvent, touchDownHandler); } /// /// Registers for mouse or touch up. /// /// The element. /// The handler. public static void RegisterForMouseOrTouchUp(this FrameworkElement element, EventHandler handler) { RegisterForMouseOrTouchUp(element, null, handler); } /// /// Registers for preview mouse or touch down. /// /// The element. /// The relative to. /// The handler. public static void RegisterForPreviewMouseOrTouchDown(this FrameworkElement element, FrameworkElement relativeTo, EventHandler handler) { bool mousePressed = false; bool touchDown = false; MouseButtonEventHandler previewMouseDownHandler = (x, e) => { if (!touchDown) { mousePressed = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = e.GetPosition }; handler(element, args); e.Handled = args.Handled; } else { touchDown = false; } }; element.AddHandler(FrameworkElement.PreviewMouseDownEvent, previewMouseDownHandler); //element.PreviewMouseDown += previewMouseDownHandler; EventHandler previewTouchDownHandler = (x, e) => { if (!mousePressed) { touchDown = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.X, e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = (s) => { return e.GetTouchPoint(s).Position; }, TouchDevice = e.TouchDevice, }; handler(element, args); e.Handled = args.Handled; } else { touchDown = false; } }; //element.PreviewTouchDown += previewTouchDownHandler; element.AddHandler(FrameworkElement.PreviewTouchDownEvent, previewTouchDownHandler); MouseButtonEventHandler previewMouseUpHandler = (_, __) => { touchDown = false; mousePressed = false; }; //element.PreviewMouseUp += previewMouseUpHandler; element.AddHandler(FrameworkElement.PreviewMouseUpEvent, previewMouseUpHandler); } /// /// Registers for preview mouse or touch down. /// /// The element. /// The handler. public static void RegisterForPreviewMouseOrTouchDown(this FrameworkElement element, EventHandler handler) { RegisterForPreviewMouseOrTouchDown(element, null, handler); } /// /// Registers for preview mouse or touch up. /// /// The element. /// The relative to. /// The handler. public static void RegisterForPreviewMouseOrTouchUp(this FrameworkElement element, FrameworkElement relativeTo, EventHandler handler) { bool mouseReleased = false; bool touchReleased = false; MouseButtonEventHandler previewMouseUpHandler = (x, e) => { if (!touchReleased) { mouseReleased = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = e.GetPosition }; handler(element, args); e.Handled = args.Handled; } else { touchReleased = false; } }; //element.PreviewMouseUp += previewMouseUpHandler; element.AddHandler(FrameworkElement.PreviewMouseUpEvent, previewMouseUpHandler); EventHandler previewTouchHandler = (x, e) => { if (!mouseReleased) { touchReleased = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.X, e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = (s) => { return e.GetTouchPoint(s).Position; }, TouchDevice = e.TouchDevice, }; handler(element, args); e.Handled = args.Handled; } else { touchReleased = false; } }; //element.PreviewTouchUp += previewTouchHandler; element.AddHandler(FrameworkElement.PreviewTouchUpEvent, previewTouchHandler); EventHandler previewTouchDownHandler = (_, __) => { touchReleased = false; mouseReleased = false; }; //element.PreviewTouchDown += previewTouchDownHandler; element.AddHandler(FrameworkElement.PreviewTouchDownEvent, previewTouchDownHandler); } /// /// Registers for preview mouse or touch up. /// /// The element. /// The handler. public static void RegisterForPreviewMouseOrTouchUp(this FrameworkElement element, EventHandler handler) { RegisterForPreviewMouseOrTouchUp(element, null, handler); } /// /// Registers for mouse or touch move. /// /// The element. /// The relative to. /// The handler. public static void RegisterForMouseOrTouchMove(this FrameworkElement element, FrameworkElement relativeTo, EventHandler handler) { bool _isTouch = false; MouseEventHandler mouseHandler = (x, e) => { if (!_isTouch) { var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = e.GetPosition }; handler(element, args); e.Handled = args.Handled; } }; //element.MouseMove += mouseHandler; element.AddHandler(FrameworkElement.MouseMoveEvent, mouseHandler); EventHandler touchHandler = (x, e) => { _isTouch = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.X, e.GetTouchPoint(relativeTo != null ? relativeTo : element).Position.Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = (s) => { return e.GetTouchPoint(s).Position; }, TouchDevice = e.TouchDevice, }; handler(element, args); e.Handled = args.Handled; }; //element.TouchMove += touchHandler; element.AddHandler(FrameworkElement.TouchMoveEvent, touchHandler); } /// /// Registers for mouse or touch move. /// /// The element. /// The handler. public static void RegisterForMouseOrTouchMove(this FrameworkElement element, EventHandler handler) { RegisterForMouseOrTouchMove(element, null, handler); } /// /// Registers for mouse or stylus move. /// /// The element. /// The relative to. /// The handler. public static void RegisterForMouseOrStylusMove(this FrameworkElement element, FrameworkElement relativeTo, EventHandler handler) { bool _isTouch = false; MouseEventHandler mouseHandler = (x, e) => { if (!_isTouch) { var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = e.GetPosition }; handler(element, args); e.Handled = args.Handled; if (Mouse.LeftButton == MouseButtonState.Pressed) { var a = 5; } } }; //element.MouseMove += mouseHandler; element.AddHandler(FrameworkElement.MouseMoveEvent, mouseHandler); StylusEventHandler touchHandler = (x, e) => { _isTouch = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = (s) => { return e.GetPosition(s); }, StylusDevice = e.StylusDevice, }; handler(element, args); e.Handled = args.Handled; }; //element.TouchMove += touchHandler; element.AddHandler(FrameworkElement.StylusMoveEvent, touchHandler); } /// /// Registers for mouse or stylus move. /// /// The element. /// The handler. public static void RegisterForMouseOrStylusMove(this FrameworkElement element, EventHandler handler) { RegisterForMouseOrStylusMove(element, null, handler); } /// /// Registers for mouse or stylus move. /// /// The element. /// The relative to. /// The handler. public static void RegisterForPreviewMouseOrStylusMove(this FrameworkElement element, FrameworkElement relativeTo, EventHandler handler) { bool _isTouch = false; MouseEventHandler mouseHandler = (x, e) => { if (!_isTouch) { var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = e.GetPosition }; handler(element, args); e.Handled = args.Handled; if (Mouse.LeftButton == MouseButtonState.Pressed) { var a = 5; } } }; //element.MouseMove += mouseHandler; element.AddHandler(FrameworkElement.PreviewMouseMoveEvent, mouseHandler); StylusEventHandler touchHandler = (x, e) => { _isTouch = true; var args = new MouseOrTouchEventArgs() { Location = new Point(e.GetPosition(relativeTo != null ? relativeTo : element).X, e.GetPosition(relativeTo != null ? relativeTo : element).Y), Source = e.Source, OriginalSource = e.OriginalSource, Handled = e.Handled, GetPositionAction = (s) => { return e.GetPosition(s); }, StylusDevice = e.StylusDevice, }; handler(element, args); e.Handled = args.Handled; }; //element.TouchMove += touchHandler; element.AddHandler(FrameworkElement.StylusMoveEvent, touchHandler); } /// /// Registers for mouse or stylus move. /// /// The element. /// The handler. public static void RegisterForPreviewMouseOrStylusMove(this FrameworkElement element, EventHandler handler) { RegisterForPreviewMouseOrStylusMove(element, null, handler); } #endregion #region Loaded /// /// Registers for the element loaded event. if the element is already loaded will invoke the handler immediately. /// /// The element. /// The handler. public static void RegisterForLoadedOrNow(this FrameworkElement element, EventHandler handler) { if (element.IsLoaded) { handler(element, new EventArgs()); } else { bool isLoaded = false; element.AddHandler(FrameworkElement.LoadedEvent, new RoutedEventHandler((x, y) => { if (!isLoaded) { isLoaded = true; handler(element, new EventArgs()); } })); } } #endregion #region Visual Tree /// /// A recursive search for a child of type T in memory and not on logical/visual tree. /// /// /// The element. /// public static T FindChildOffline(this FrameworkElement element) where T : DependencyObject { if (element == null) return null; PropertyInfo contentProp = element.GetType().GetProperty("Child"); if (contentProp == null) { contentProp = element.GetType().GetProperty("Content"); } if (contentProp != null) { var value = contentProp.GetValue(element); if (value != null) { if (value.GetType() == typeof(T)) { return (T)value; } else { return FindChildOffline(value as FrameworkElement); } } } if (element is Panel) { foreach (var child in (element as Panel).Children.OfType()) { if (child.GetType() == typeof(T)) { return child as T; } else { var result = FindChildOffline(child); if (result != null) { return result; } } } } var contentAtt = element.GetType().GetCustomAttribute(); if (contentAtt != null) { contentProp = element.GetType().GetProperty(contentAtt.Name); if (contentProp != null) { var content = contentProp.GetValue(element); if (content != null) { if (content is IEnumerable) { foreach (var child in (content as IEnumerable)) { if (child.GetType() == typeof(T)) { return child as T; } else { var result = FindChildOffline(child as FrameworkElement); if (result != null) { return result; } } } } else { var result = FindChildOffline(content as FrameworkElement); if (result != null) { return result; } } } } } return null; } #endregion #region Bitmaps /// /// Creates a bitmap source from the framework element. /// /// The element. /// public static RenderTargetBitmap TakeSnapshot(this FrameworkElement element) { int nWidth = (int)Math.Ceiling(element.ActualWidth); int nHeight = (int)Math.Ceiling(element.ActualHeight); RenderTargetBitmap oTargetBitmap = new RenderTargetBitmap( nWidth, nHeight, 96, 96, PixelFormats.Pbgra32 ); DrawingVisual oDrawingVisual = new DrawingVisual(); using (DrawingContext oDrawingContext = oDrawingVisual.RenderOpen()) { VisualBrush oVisualBrush = new VisualBrush(element) { Stretch = Stretch.Fill }; oDrawingContext.DrawRectangle( oVisualBrush, null, new Rect( new Point(), new Size(nWidth, nHeight) ) ); oDrawingContext.Close(); oTargetBitmap.Render(oDrawingVisual); } return oTargetBitmap; } #endregion #region Animations /// /// Starts a double animation on the specified property. /// /// The element. /// The property. /// The duration. /// The acceleration. /// The deceleration. /// The on complete. /// public static DoubleAnimation StartDoubleAnimation(this FrameworkElement element, DependencyProperty property, TimeSpan duration, double to, double? from = null, double? acceleration = null, double? deceleration = null, Action onComplete = null, bool autoReverse = false) { DoubleAnimation ani = new DoubleAnimation(); ani.Duration = duration; ani.AutoReverse = autoReverse; if (acceleration.HasValue) { ani.AccelerationRatio = acceleration.Value; } if (deceleration.HasValue) { ani.DecelerationRatio = deceleration.Value; } if (ani.From.HasValue) { ani.From = from.Value; } ani.To = to; ani.Completed += (x, y) => onComplete?.Invoke(); element.BeginAnimation(property, ani); return ani; } #endregion #region Size /// /// Ensures the element has height other than NaN. If the element height equals NaN, the method will assign ActualHeight to Height. /// /// The element. public static void EnsureHeight(this FrameworkElement element) { if (double.IsNaN(element.Height)) { element.Height = element.ActualHeight; } } #endregion }