在WPF中向鼠标旋转图形(如模拟转盘)

时间:2009-06-07 22:45:51

标签: c# wpf user-interface controls

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

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

我如何创建其中一个?一个人已经存在吗?

3 个答案:

答案 0 :(得分:19)

我没有看到这样的任何控件(虽然我看了WPF控件供应商提供的所有控件已经有一段时间了),但是创建一个控件相对简单。

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

<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”可确保控件围绕其中心旋转,而不是围绕左上角旋转;我们也必须在角度计算中对此进行补偿。

在控件的代码隐藏文件中,添加鼠标处理程序和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;
            }
        }
    }
}

捕获鼠标确保您的控件将继续获得鼠标更新,即使用户将鼠标移出控件(直到他们放开点击),并获取鼠标相对于当前元素的位置(控制),无论控件在屏幕上实际呈现的位置如何,您的计算应始终相同。

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

在解决方案中使用控件很简单;只需添加:

<local:VolumeControl />

如果要将旋钮的值绑定到应用程序中的某些内容,可以绑定到VolumeControl上的Angle属性;该值目前以度为单位,但可以添加一个额外的属性,以转换为度数角度和对您有意义的值(例如,0到10之间的值)。

答案 1 :(得分:3)

要添加到该帖子,鼠标点和对象点之间的角度计算如下:

dot = currentLocation.X * objectPosition.X + currentLocation.Y * objectPosition.Y;
angle = Math.Acos(dot);

答案 2 :(得分:0)

在我的情况下,我动态创建了将朝鼠标方向旋转的形状。为了解决这个问题,我使用了轻量级功能我需要的只是:

  • 当前所选形状的中心点
  • 上次鼠标悬停步骤的要点
  • 从当前鼠标悬停步骤开始的点

没有必要使用Math库中的方法。我计算的角度取决于当前鼠标在点与前一个鼠标在点之间的差异以及与中心点相关的位置。最后,我在当前对象的exisitng角度上添加角度。

Suppress for statement