在WPF中向鼠标旋转图形(类似于模拟拨盘) [英] Rotate graphic towards mouse in WPF (like an analog dial)

查看:405
本文介绍了在WPF中向鼠标旋转图形(类似于模拟拨盘)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在WPF / C#中,如何旋转图形以面对当前鼠标位置?

In WPF/C# how would I rotate a "graphic" to face the current mouse position?

基本上我想要的是滚轮 UI控件(例如模拟音量拨盘)。我希望能够单击并拖动转盘,并且它会旋转以跟随鼠标。然后,当我释放鼠标时,它将停止跟随(显然!)。

Basically what I want is a "wheel" UI Control (like an analog volume dial). I want to be able to click and drag the dial and it will rotate to follow the mouse. Then when I release the mouse it will stop following (obviously!).

我将如何创建其中之一?

How would I create one of these? does one already exist somewhere?

推荐答案

我还没有看到任何类似的控件(尽管自从我看了已经有一段时间了) WPF控件供应商提供的所有控件),但是创建一个控件相对简单。

I haven't seen any controls like this around (though it's been a while since I looked at all of the controls that WPF control vendors were offering), but it's relatively straightforward to create one.

您要做的就是创建一个包含您可以旋转以跟随鼠标的图像(或XAML绘图)。然后,将RotateTransform绑定到自定义控件上的 Angle DependencyProperty,以便在更新 angle时,图像/绘图旋转以匹配:

All you'd have to do is create a custom control containing an Image (or XAML drawing) that you can rotate to follow the mouse. Then, bind a RotateTransform to an 'Angle' DependencyProperty on your custom control so that when 'angle' is updated, the image/drawing rotates to match:

<UserControl x:Class="VolumeControlLibrary.VolumeControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:VolumeControlLibrary"
             Height="60" Width="60">
    <Image Source="/VolumeControl;component/knob.png" RenderTransformOrigin="0.5,0.5" >
        <Image.RenderTransform>
            <RotateTransform Angle="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:VolumeControl}}, Path=Angle}"/>
        </Image.RenderTransform>
    </Image>
</UserControl>

将RenderTransformOrigin设置为 0.5,0.5可确保控件围绕其中心旋转,而不是围绕其旋转左上角;我们也必须在角度计算中对此进行补偿。

Setting RenderTransformOrigin to "0.5, 0.5" ensures that the control rotates around its center, rather than rotating around the top left corner; we'll have to compensate for this in the angle calculation too.

在用于控制的文件后面的代码中,添加鼠标处理程序和Angle DependencyProperty:

In the code behind file for your control, add handlers for the mouse and the Angle DependencyProperty:

public partial class VolumeControl : UserControl
{
    // Using a DependencyProperty backing store for Angle.
    public static readonly DependencyProperty AngleProperty =
        DependencyProperty.Register("Angle", typeof(double), typeof(VolumeControl), new UIPropertyMetadata(0.0));

    public double Angle
    {
        get { return (double)GetValue(AngleProperty); }
        set { SetValue(AngleProperty, value); }
    }

    public VolumeControl()
    {
        InitializeComponent();
        this.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
        this.MouseUp += new MouseButtonEventHandler(OnMouseUp);
        this.MouseMove += new MouseEventHandler(OnMouseMove);
    }

    private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Mouse.Capture(this);
    }

    private void OnMouseUp(object sender, MouseButtonEventArgs e)
    {
        Mouse.Capture(null);
    }

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        if (Mouse.Captured == this)
        {
            // Get the current mouse position relative to the volume control
            Point currentLocation = Mouse.GetPosition(this);

            // We want to rotate around the center of the knob, not the top corner
            Point knobCenter = new Point(this.ActualHeight / 2, this.ActualWidth / 2);

            // Calculate an angle
            double radians = Math.Atan((currentLocation.Y - knobCenter.Y) / 
                                       (currentLocation.X - knobCenter.X));
            this.Angle = radians * 180 / Math.PI;

            // Apply a 180 degree shift when X is negative so that we can rotate
            // all of the way around
            if (currentLocation.X - knobCenter.X < 0)
            {
                this.Angle += 180;
            }
        }
    }
}

捕获鼠标可确保即使用户将鼠标从控件上移开(直到他们放开单击),控件也将继续获取鼠标更新,并且通过获取鼠标相对于当前元素(控件)的位置,您可以

Capturing the mouse ensures that your control will continue to get mouse updates even when the user mouses off of the control (until they let go of the click), and by getting the position of the mouse relative to the current element (the control), your calculation should always be the same regardless of where the control actually renders on screen.

在此示例中,当鼠标移动时,我们将计算控件与控件中心之间的角度。控件,然后将此角度设置为我们创建的Angle DependencyProperty。由于我们要显示的图像已绑定到该angle属性,因此WPF会自动应用新值,从而导致旋钮随着鼠标移动而旋转。

In this example, when the mouse moves we calculate the angle between it and the center of the control, and then set this angle to the Angle DependencyProperty we created. Since the image we're displaying is bound to this angle property, WPF automatically applies the new value, which results in the knob rotating in combination with the mouse moving.

使用解决方案中的控件很容易;只需添加:

Using the control in your solution is easy; just add:

<local:VolumeControl />

如果要将旋钮的值绑定到某些对象,则可以绑定到VolumeControl上的Angle属性。在您的应用程序中;该值当前以度为单位,但是可以添加一个附加属性,以在以度为单位的角度和对您有意义的值(例如,介于0到10之间的值)之间进行转换。

You would bind to the Angle property on VolumeControl if you wanted to bind the value of the knob to something in your application; that value is currently in degrees, but could add an additional property to convert between an angle in degrees and a value that makes sense to you (say, a value from 0 - 10).

这篇关于在WPF中向鼠标旋转图形(类似于模拟拨盘)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆