private void mainGrid_PreviewMouseUp(object sender, MouseButtonEventArgs e) { // is this the end of a drag operation? if (this.dragTumbler != null) { double offset = -Canvas.GetTop(this.dragTumbler); Point mousePt = Mouse.GetPosition(this.mainGrid); if (mousePt.Equals(this.dragPt)) { // user clicked on tumbler without dragging, select the clicked-on value offset += mousePt.Y - (this.mainGrid.ActualHeight / 2); } // find the Canvas offset for the value closest to where the drag ended TumblerData td = this.dragTumbler.Tag as TumblerData; double itemHeight = this.dragTumbler.ActualHeight / (td.Values.Count); double newVal = offset / itemHeight + 2; int iVal = (int)Math.Round(newVal); // update index, limit to valid values. The update will cause NotifyPropertyChanged which // will animate the tumbler into the appropriate position for the selected value td.SelectedValueIndex = Math.Min(Math.Max(0, iVal), td.Values.Count - 1); this.dragTumbler = null; } if (this.mainGrid.IsMouseCaptured && this.AlwaysOpen) { this.mainGrid.ReleaseMouseCapture(); } }
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { TumblerData td = values[0] as TumblerData; bool isOpen = (bool)values[1]; int currentIndex = (int)values[2]; return(isOpen || (td != null && currentIndex == td.SelectedValueIndex) ? Visibility.Visible : Visibility.Hidden); }
/// <summary> /// Mouse wheel handler for tumblers. This is not a fired event because we need to mouse capture on the main grid /// so we can know when to close the control. Instead this event gets called via the MouseWheel event on the main grid. /// </summary> /// <param name="tumbler">The tumbler (grid) that should receive the mouse wheel event</param> /// <param name="e">the MouseWheelEventArgs forwarded from the main grid MouseWheel event</param> private void Tumbler_PreviewMouseWheel(Grid tumbler, MouseWheelEventArgs e) { if (tumbler != null) { TumblerData td = tumbler.Tag as TumblerData; // Each click in the mouse will increment or decrement the tumbler value by one int newIdx = td.SelectedValueIndex + (e.Delta > 0 ? -1 : 1); if (newIdx >= 0 && newIdx < td.Values.Count) { // Set the new index which will cause NotifyPropertyChanged to fire, which in turn will cause // the binding/converter to re-evaluate, which will result in the tumbler animating to the correct // canvas offset. td.SelectedValueIndex = newIdx; } } }
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // TumblerDataToOffsetConverter is just a shell for getting SelectedValueChanged event and using it to adjust the items grid // canvas offset. Reason we don't just bind the Canvas.Top property directly is because that binding will // get lost when we manually set Canvas.Top via drag support Grid tumbler = values[0] as Grid; TumblerData td = tumbler.Tag as TumblerData; if (td != null) { double itemHeight = tumbler.ActualHeight / (td.Values.Count); double offset = td.SelectedValueIndex > 0 ? -(td.SelectedValueIndex - 2) * itemHeight : itemHeight * 2; // animate from current position to value offset DoubleAnimation da = new DoubleAnimation(); da.From = Canvas.GetTop(tumbler); da.To = offset; da.Duration = new Duration(TimeSpan.FromMilliseconds(100)); tumbler.BeginAnimation(Canvas.TopProperty, da); } return(values[2]); }