WPF UI can be Drag around using mouseMove stream Buffer of two element calculation of Delta: (1) Observe 3 streams: mouseDown, mouseUp, mouseMove. The first two are point event and need duration to join to mouseMove. (2) The duration is skip until mouseDown take until mouseUp (3) Delta is the difference between two mouseMove sampling inside Buffer(2,2). Note that Buffer(count, skip) skip=count is standard, skip>count skip and skip<count is overlapping. Buffer means pile up multiple point into one tallypublic MainWindow() { InitializeComponent(); var mouseDown = from evt in Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(h => cv.MouseDown += h, h => cv.MouseDown -= h) select evt.EventArgs.GetPosition(this); var mouseUp = from evt in Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(h => MouseUp += h, h => MouseUp -= h) select evt.EventArgs.GetPosition(this); var mouseMove = from evt in Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(h => MouseMove += h, h => MouseMove -= h) select evt.EventArgs.GetPosition(this); var q = Observable.Join( mouseDown, mouseMove.Buffer(2, 2), _ => mouseMove.SkipUntil(mouseDown).TakeUntil(mouseUp), _ => Observable.Empty<Unit>(), (d, consecPts) =>new Point(consecPts[1].X - consecPts[0].X, consecPts[1].Y - consecPts[0].Y)); q.Subscribe(delta => { Canvas.SetLeft(cv, Canvas.GetLeft(cv) + delta.X); Canvas.SetTop(cv, Canvas.GetTop(cv) + delta.Y); }); // Side Note: To allow resizing do the following and using Microsoft sample Resizing Adorner: // a = AdornerLayer.GetAdornerLayer(g); //g=Canvas for layout // a.Add(new ResizingAdorner(cv)); // cv= any UIElement inside g } // AdornerLayer adornerLayer; } public class ResizingAdorner : Adorner { Thumb topLeft, topRight, bottomLeft, bottomRight; VisualCollection visualChildren; public ResizingAdorner(UIElement adornedElement) : base(adornedElement) { visualChildren = new VisualCollection(this); BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE); BuildAdornerCorner(ref topRight, Cursors.SizeNESW); BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW); BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE); bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft); bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight); topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft); topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight); } #region Handle Resizing from Thumb void HandleBottomRight(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = this.AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; FrameworkElement parentElement = adornedElement.Parent as FrameworkElement; EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height); } void HandleBottomLeft(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; // Ensure that the Width and Height are properly initialized after the resize. EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height); } void HandleTopRight(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = this.AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; FrameworkElement parentElement = adornedElement.Parent as FrameworkElement; EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); } void HandleTopLeft(object sender, DragDeltaEventArgs args) { FrameworkElement adornedElement = AdornedElement as FrameworkElement; Thumb hitThumb = sender as Thumb; if (adornedElement == null || hitThumb == null) return; EnforceSize(adornedElement); adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width); adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height); } #endregion // Arrange thumbs relative to Adorner Center protected override Size ArrangeOverride(Size finalSize) { double desiredWidth = AdornedElement.DesiredSize.Width; double desiredHeight = AdornedElement.DesiredSize.Height; double adornerWidth = this.DesiredSize.Width; double adornerHeight = this.DesiredSize.Height; topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight)); topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight)); bottomLeft.Arrange(new Rect(-adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight)); bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight)); return finalSize; } void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor) { if (cornerThumb != null) return; cornerThumb = new Thumb(); // Set some arbitrary visual characteristics. cornerThumb.Cursor = customizedCursor; cornerThumb.Height = cornerThumb.Width = 10; cornerThumb.Opacity = 0.40; cornerThumb.Background = new SolidColorBrush(Colors.MediumBlue); visualChildren.Add(cornerThumb); // Must add to the tree to arrange } void EnforceSize(FrameworkElement adornedElement) { if (adornedElement.Width.Equals(Double.NaN)) adornedElement.Width = adornedElement.DesiredSize.Width; if (adornedElement.Height.Equals(Double.NaN)) adornedElement.Height = adornedElement.DesiredSize.Height; FrameworkElement parent = adornedElement.Parent as FrameworkElement; if (parent != null) { adornedElement.MaxHeight = parent.ActualHeight; adornedElement.MaxWidth = parent.ActualWidth; } } protected override int VisualChildrenCount { get { return visualChildren.Count; } } protected override Visual GetVisualChild(int index) { return visualChildren[index]; } }
Friday, August 17, 2012
Drag Canvas around using Rx
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment