WPF 触摸式旋钮制作

触摸方式下的旋钮制作,通过旋转小圆来实现旋钮控制。

MainWindow:

<Window x:Class="PMA.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:PMA">
    <Grid>
      
        <my:SliderRotation HorizontalAlignment="Left" Margin="289,92,0,0" x:Name="sliderRotation1" VerticalAlignment="Top" Height="111" Width="107"
                           ValueAdd="sliderRotation1_ValueAdd" ValueReduced="sliderRotation1_ValueReduced" ValueChanged="sliderRotation1_ValueChanged" />
        <TextBlock HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBlock5" Text="1.用户设置的最大值" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="114,12,0,0" Name="textBlock1" Text="{Binding ElementName=sliderRotation1, Path=Maximum}" VerticalAlignment="Top" />
        
        <TextBlock HorizontalAlignment="Left" Margin="12,41,0,0" Name="textBlock6" Text="2.用户设置的最小值" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="114,41,0,0" Name="textBlock2" Text="{Binding ElementName=sliderRotation1, Path=Minimum}" VerticalAlignment="Top" />
        
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="12,70,0,0" Name="textBlock3" Text="3当前值" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="76,70,0,0" Name="textBlock7" Text="{Binding ElementName=sliderRotation1, Path=Value}" VerticalAlignment="Top" />
        
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="12,99,0,0" Name="textBlock4" Text="旋钮旋转的最小角度" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="133,99,0,0" Name="textBlock8" Text="{Binding ElementName=sliderRotation1, Path=SmallAngle}" VerticalAlignment="Top" />
        
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="12,128,0,0" Name="textBlock9" Text="旋转最小角度的变化值" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="140,128,0,0" Name="textBlock10" Text="{Binding ElementName=sliderRotation1, Path=SmallChange}" VerticalAlignment="Top" />
        
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="12,158,0,0" Name="textBlock11" Text="数值增加事件触发次数" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="147,158,0,0" Name="textBlockAdd" VerticalAlignment="Top" />
        
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="12,187,0,0" Name="textBlock13" Text="数值减小事件触发次数" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="147,187,0,0" Name="textBlockReduced" VerticalAlignment="Top" />
       
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="12,216,0,0" Name="textBlock12" Text="数值改变事件触发次数" VerticalAlignment="Top" />
        <TextBlock HorizontalAlignment="Left" Margin="147,216,0,0" Name="textBlockChanged" VerticalAlignment="Top" />
    </Grid>
</Window>

 

 

 

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.Navigation;
using System.Windows.Shapes;

namespace PMA
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        int add = 0;
        int reduced = 0;
        int changed = 0;
        public MainWindow()
        {
            InitializeComponent();
        }

        private void sliderRotation1_ValueAdd(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            add++;
            textBlockAdd.Text = add.ToString();
        }

        private void sliderRotation1_ValueReduced(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            reduced++;
            textBlockReduced.Text = reduced.ToString();
        }

        private void sliderRotation1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            changed++;
            textBlockChanged.Text = changed.ToString();
        }
    }
}
 

 

 

UserControl:

<UserControl x:Class="PMA.SliderRotation"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Name="sliderRotation" Foreground="DodgerBlue" BorderBrush="Black" >
    <Viewbox>
        <Grid>
            <Canvas Name="canvas" Width="80" Height="80" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Ellipse Height="80" Width="80" Name="ellipseBack" 
                         Stroke="{x:Null}" 
                         Fill="{Binding ElementName=sliderRotation, Path=BorderBrush}" 
                         MouseLeave="ellipseBack_MouseLeave" 
                         MouseMove="ellipseBack_MouseMove" 
                         MouseLeftButtonUp="ellipseBack_MouseUp" 
                         MouseLeftButtonDown="ellipseBack_MouseDown" 
                         StrokeThickness="0.5">
                    <!--<Ellipse.Effect>--><!--Effect:外部光圈--><!--
                        <DropShadowEffect Direction="270" Color="Black" Opacity="0.5" BlurRadius="3" ShadowDepth="1"/>
                    </Ellipse.Effect>-->
                </Ellipse>
                <Ellipse Height="20" Name="handle" Stroke="#20000000" Width="20" Fill="{Binding ElementName=sliderRotation, Path=Foreground}" RenderTransformOrigin="0.5,2" 
                         IsHitTestVisible="False" Margin="30,0,0,0">
                    <Ellipse.RenderTransform>
                        <RotateTransform x:Name="rotate" />
                      <!--RotateTransform:能够让某对象产生旋转变化,根据中心点进行顺时针旋转或逆时针旋转。-->
                    </Ellipse.RenderTransform>
                </Ellipse>
            </Canvas>
        </Grid>
    </Viewbox>
</UserControl>

 

 

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.Navigation;
using System.Windows.Shapes;

namespace PMA
{
    /// <summary>
    /// SliderRotation.xaml 的交互逻辑
    /// </summary>
    public partial class SliderRotation : UserControl
    {
        #region 私有属性

        private Point cen;   //中心点
        private Point first;  //初始状态位置
        private Point second;  //

        private bool flag = false;
        private double angle;   //旋钮实际旋转角度
        private double turns = 0;  //旋钮旋转圈数
        private double valueChangeToChange;   //旋钮当前旋转角度,正数为顺时针 负数为逆时针

        #endregion

        #region 公有属性

        /// <summary>
        /// 获取或设置Value数值
        /// </summary>
        public double Value         
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty;

        /// <summary>
        /// 获取或设置最小旋转角度
        /// </summary>
        public double SmallAngle    
        {
            get { return (double)GetValue(SmallAngleProperty); }
            set { SetValue(SmallAngleProperty, value); }
        }
        public static readonly DependencyProperty SmallAngleProperty;

        /// <summary>
        /// 获取或设置最小旋转角度代表的Value数值
        /// </summary>
        public double SmallChange    
        {
            get { return (double)GetValue(SmallChangeProperty); }
            set { SetValue(SmallChangeProperty, value); }
        }
        public static readonly DependencyProperty SmallChangeProperty;

        /// <summary>
        /// 获取或设置最大Value数值
        /// </summary>
        public double Maximum     
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
        public static readonly DependencyProperty MaximumProperty;

        /// <summary>
        /// 获取或设置最小Value数值
        /// </summary>
        public double Minimum    
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }
        public static readonly DependencyProperty MinimumProperty;

        #endregion

        public SliderRotation()
        {
            InitializeComponent();
        }

        static SliderRotation()
        {
            ValueProperty = DependencyProperty.RegisterAttached(
                "Value",
                typeof(double),
                typeof(SliderRotation),
                new FrameworkPropertyMetadata((double)0, new PropertyChangedCallback(ValuePropertyChangedCallback)));
            SmallAngleProperty = DependencyProperty.RegisterAttached(
                "SmallAngle",
                typeof(double),
                typeof(SliderRotation),
                new FrameworkPropertyMetadata((double)10, new PropertyChangedCallback(SmallAnglePropertyChangedCallback)));
            SmallChangeProperty = DependencyProperty.RegisterAttached(
                "SmallChange",
                typeof(double),
                typeof(SliderRotation),
                new FrameworkPropertyMetadata((double)1));
            MaximumProperty = DependencyProperty.RegisterAttached(
                "Maximum",
                typeof(double),
                typeof(SliderRotation),
                new FrameworkPropertyMetadata((double)36));
            MinimumProperty = DependencyProperty.RegisterAttached(
                "Minimum",
                typeof(double),
                typeof(SliderRotation),
                new FrameworkPropertyMetadata((double)0));
        }

        private static void ValuePropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
        {
            if (sender != null && sender is SliderRotation)
            {
                SliderRotation sliderRotation = sender as SliderRotation;
                RoutedPropertyChangedEventArgs<object> valueArg =
                    new RoutedPropertyChangedEventArgs<object>(arg.OldValue, arg.NewValue, ValueChangedEvent);
                sliderRotation.RaiseEvent(valueArg);

                if (sliderRotation.valueChangeToChange > 0)
                {
                    RoutedPropertyChangedEventArgs<object> valueAddArg =
                        new RoutedPropertyChangedEventArgs<object>(arg.OldValue, arg.NewValue, ValueAddEvent);
                    sliderRotation.RaiseEvent(valueAddArg);

                }
                else if (sliderRotation.valueChangeToChange < 0)
                {
                    RoutedPropertyChangedEventArgs<object> valueReducedArg =
                       new RoutedPropertyChangedEventArgs<object>(arg.OldValue, arg.NewValue, ValueReducedEvent);
                    sliderRotation.RaiseEvent(valueReducedArg);
                }
            }
        }

        private static void SmallAnglePropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
        {
            //if (sender != null && sender is SliderRotation)
            //{
            //    SliderRotation sliderRotation = sender as SliderRotation;
            //    double SmallellipesStaff = (sliderRotation.ellipesStaff.Height + sliderRotation.ellipesStaff.Width) * sliderRotation.SmallAngle / 720;
            //    DoubleCollection doubleCollection = new DoubleCollection();
            //    doubleCollection.Add(0.5);
            //    doubleCollection.Add(SmallellipesStaff - 0.45);
            //    sliderRotation.ellipesStaff.StrokeDashArray = doubleCollection;
            //}
        }


        #region 事件路由

        public event RoutedPropertyChangedEventHandler<object> ValueChanged
        {
            add
            {
                this.AddHandler(ValueChangedEvent, value);
            }

            remove
            {
                this.RemoveHandler(ValueChangedEvent, value);
            }
        }

        public event RoutedPropertyChangedEventHandler<object> ValueAdd
        {
            add
            {
                this.AddHandler(ValueAddEvent, value);
            }

            remove
            {
                this.RemoveHandler(ValueAddEvent, value);
            }
        }

        public event RoutedPropertyChangedEventHandler<object> ValueReduced
        {
            add
            {
                this.AddHandler(ValueReducedEvent, value);
            }

            remove
            {
                this.RemoveHandler(ValueReducedEvent, value);
            }
        }


        public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(
            "ValueChanged",
            RoutingStrategy.Bubble,
            typeof(RoutedPropertyChangedEventHandler<object>),
            typeof(SliderRotation));

        public static readonly RoutedEvent ValueAddEvent =EventManager.RegisterRoutedEvent(
            "ValueAdd", 
            RoutingStrategy.Bubble, 
            typeof(RoutedPropertyChangedEventHandler<object>), 
            typeof(SliderRotation));

        public static readonly RoutedEvent ValueReducedEvent =EventManager.RegisterRoutedEvent(
            "ValueReduced", 
            RoutingStrategy.Bubble, 
            typeof(RoutedPropertyChangedEventHandler<object>), 
            typeof(SliderRotation));

        #endregion


        private double GetAngle(Point point)     //获取点到中心的角度      构造平面直角坐标系 计算点在该坐标系与y轴(正方向)的夹角
        {
            const double M_PI = 3.1415926535897;
            if (point.X >= 0)
            {
                double hypotenuse = Math.Sqrt(point.X * point.X + point.Y * point.Y);
                return Math.Acos(point.Y / hypotenuse) * 180 / M_PI;
            }
            else
            {
                double hypotenuse = Math.Sqrt(point.X * point.X + point.Y * point.Y);
                return 360 - Math.Acos(point.Y / hypotenuse) * 180 / M_PI;
            }
        }

        private void ellipseBack_MouseDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            flag = true;
            cen = new Point(ellipseBack.Width / 2, ellipseBack.Height / 2);
            first = new Point(e.GetPosition(canvas).X - cen.X, cen.Y - e.GetPosition(canvas).Y);
        }


        private void ellipseBack_MouseUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            flag = false;
            angle = rotate.Angle;
        }

        private void ellipseBack_MouseLeave(object sender, MouseEventArgs e)
        {
            e.Handled = true;

            flag = false;
            angle = rotate.Angle;
        }

        private void ellipseBack_MouseMove(object sender, MouseEventArgs e)
        {
            e.Handled = true;        //停止路由事件向上传递

            if (flag)
            {
                second = new Point(e.GetPosition(canvas).X - cen.X, cen.Y - e.GetPosition(canvas).Y);    //确定鼠标移动的点坐标(相对中心点的位置)
               
                if (second == new Point(0,0))
                {
                    return;
                }

                double anglePointToPoint = GetAngle(second) - GetAngle(first);        //得到鼠标移动之前与鼠标移动之后之间的夹角

                first = second;

                if (Math.Abs(anglePointToPoint) > 90)                               //夹角如果大于90度忽略(大于90度的夹角有可能是计算错误得出来的)
                {
                    anglePointToPoint = 0;
                }

                angle += anglePointToPoint;                                       //

                valueChangeToChange = (int)((angle - rotate.Angle) / SmallAngle) * SmallChange;    //根据角度计算出夹角的数值

                if (valueChangeToChange != 0)
                {
                    rotate.Angle = angle - angle % SmallAngle;                                  //计算出旋转角度

                    double value = (Value + valueChangeToChange) - (Value + valueChangeToChange) % SmallChange;   //计算出属性值

                    if (value < Minimum)                                      //属性值小于最小值 则 赋予最小值
                    {
                        Value = Minimum;
                    }
                    else if (value > Maximum)                                 //属性值大于最大值 则 赋予最大值
                    {
                        Value = Maximum;
                    }
                    else
                    {
                        Value = value;
                    }

                    if (angle > 360 && rotate.Angle > 360)                     //旋钮旋转超过 360度 或小于零度 将该角度计算到圈数中 
                    {
                        angle -= 360;
                        rotate.Angle -= 360;
                        turns++;
                    }
                    else if (angle < 0 && rotate.Angle < 360)
                    {
                        angle += 360;
                        rotate.Angle += 360;
                        turns--;
                    }
                }
            }
        }

    }
}
 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值