A Knob Slider Control

I replace the template of the Slider control with a knob template and handle some mouse events to implement rotation. The code snippets below shows the details:


<Window x:Class="WpfApplication16.Window1"
        Title="Window1" Height="300" Width="300">    
        <my:ValueAngleConverter x:Key="valueAngleConverter"/>
        <my:ValueTextConverter x:Key="valueTextConverter"/>
        <Slider Name="knob">
<Canvas Width="300" Height="300" Margin="5">
    <Ellipse Fill="LightBlue" Width="300" Height="300" Canvas.Left="0" Canvas.Top="0" 
                Stroke="Black" StrokeThickness="10"
    <Ellipse Fill="Black" Width="60" Height="60" Canvas.Left="120" Canvas.Top="120"/>
        <Line Stroke="Red" StrokeThickness="5" X1="150" Y1="150" X2="150" Y2="10"
        <Ellipse Fill="Red" Width="20" Height="20" Canvas.Left="140" Canvas.Top="0" 
                    <Binding RelativeSource="{RelativeSource TemplatedParent}"
                                Path="Value" Converter="{StaticResource valueTextConverter}"/>
            <RotateTransform CenterX="150" CenterY="150">
                    <MultiBinding Converter="{StaticResource valueAngleConverter}">
                        <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
                        <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
                        <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpfApplication16
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
        public Window1()

        private bool _isPressed = false;
        private Canvas _templateCanvas = null;

        private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            //Enable moving mouse to change the value.
            _isPressed = true;

        private void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            //Disable moving mouse to change the value.
            _isPressed = false;

        private void Ellipse_MouseMove(object sender, MouseEventArgs e)
            if (_isPressed)
                //Find the parent canvas.
                if (_templateCanvas == null)
                    _templateCanvas = MyHelper.FindParent<Canvas>(e.Source as Ellipse);
                    if (_templateCanvas == null) return;
                //Canculate the current rotation angle and set the value.
                const double RADIUS = 150;
                Point newPos = e.GetPosition(_templateCanvas);
                double angle = MyHelper.GetAngleR(newPos, RADIUS);
                knob.Value = (knob.Maximum - knob.Minimum) * angle / (2 * Math.PI);

    //The converter used to convert the value to the rotation angle.
    public class ValueAngleConverter : IMultiValueConverter
        #region IMultiValueConverter Members

        public object Convert(object[] values, Type targetType, object parameter, 
System.Globalization.CultureInfo culture) { double value = (double)values[0]; double minimum = (double)values[1]; double maximum = (double)values[2]; return MyHelper.GetAngle(value, maximum, minimum); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } //Convert the value to text. public class ValueTextConverter : IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture) { double v = (double)value; return String.Format("{0:F2}", v); } public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } public static class MyHelper { //Get the parent of an item. public static T FindParent<T>(FrameworkElement current) where T : FrameworkElement { do { current = VisualTreeHelper.GetParent(current) as FrameworkElement; if (current is T) { return (T)current; } } while (current != null); return null; } //Get the rotation angle from the value public static double GetAngle(double value, double maximum, double minimum) { double current = (value / (maximum - minimum)) * 360; if (current == 360) current = 359.999; return current; } //Get the rotation angle from the position of the mouse public static double GetAngleR(Point pos, double radius) { //Calculate out the distance(r) between the center and the position Point center = new Point(radius, radius); double xDiff = center.X - pos.X; double yDiff = center.Y - pos.Y; double r = Math.Sqrt(xDiff * xDiff + yDiff * yDiff); //Calculate the angle double angle = Math.Acos((center.Y - pos.Y) / r); Console.WriteLine("r:{0},y:{1},angle:{2}.", r, pos.Y, angle); if (pos.X < radius) angle = 2 * Math.PI - angle; if (Double.IsNaN(angle)) return 0.0; else return angle; } } }

This entry was posted in WPF. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s