/// <summary>Mouse/key events on the chart</summary> protected override void OnMouseDown(MouseButtonEventArgs args) { // // *** Use PreviewMouseDown to set pending MouseOps *** // *** Don't set e.Handled = true, SetPending() is enough *** // // Notes: // - MouseButton events in WPF are routed events that behave differently to WinForms. // - The order of handlers for MouseDown is: // 1) Registered class handlers // 2) OnMouseDown - base.OnMouseDown() does *not* raise the MouseDown event // 3) Handers attached to event MouseDown // - MouseDown is a 'bubbling' event, it starts at the visual tree leaf element and // bubble up the tree, stopped when a handle sets 'e.Handled = true' // - PreviewMouseDown is a tunnelling 'event', it starts at the window and drills // down the tree to the leaves. If 'e.Handled = true' in a PreviewMouseDown handler // then MouseDown is never raised, and override OnMouseDown isn't called. base.OnMouseDown(args); var location = args.GetPosition(this); // If a mouse op is already active, ignore mouse down if (MouseOperations.Active != null) { return; } // Look for the mouse op to perform if (MouseOperations.Pending[args.ChangedButton] == null && DefaultMouseControl) { switch (args.ChangedButton) { default: return; case MouseButton.Left: MouseOperations.Pending[args.ChangedButton] = new MouseOpDefaultLButton(this); break; case MouseButton.Middle: MouseOperations.Pending[args.ChangedButton] = new MouseOpDefaultMButton(this); break; case MouseButton.Right: MouseOperations.Pending[args.ChangedButton] = new MouseOpDefaultRButton(this); break; case MouseButton.XButton1: UndoNavigation(); break; case MouseButton.XButton2: RedoNavigation(); break; } } // Start the next mouse op MouseOperations.BeginOp(args.ChangedButton); // Get the mouse op, save mouse location and hit test data, then call op.MouseDown() var op = MouseOperations.Active; if (op != null && !op.Cancelled) { // Don't capture the mouse here in mouse down because that prevents // mouse up messages getting to subscribers of the MouseUp event. // Only capture the mouse when we know it's a drag operation. op.GrabClient = op.DropClient = location; // Note: in ChartControl space, not ChartPanel space op.GrabChart = op.DropChart = ClientToChart(location); op.HitResult = HitTestCS(op.GrabClient, Keyboard.Modifiers, args.ToMouseBtns(), null); op.MouseDown(args); } }