C# 在WPF中向鼠标旋转图形(如模拟拨号盘)
在WPF/C中,如何旋转“图形”以面对当前鼠标位置 基本上,我想要的是一个“轮子”UI控件(如模拟音量拨号盘)。我想能够点击和拖动拨号盘,它会随着鼠标旋转。然后,当我释放鼠标时,它将停止跟随(显然!)C# 在WPF中向鼠标旋转图形(如模拟拨号盘),c#,wpf,user-interface,controls,C#,Wpf,User Interface,Controls,在WPF/C中,如何旋转“图形”以面对当前鼠标位置 基本上,我想要的是一个“轮子”UI控件(如模拟音量拨号盘)。我想能够点击和拖动拨号盘,它会随着鼠标旋转。然后,当我释放鼠标时,它将停止跟随(显然!) 我将如何创建其中一个?某个地方已经存在这样的控件了吗?我还没有见过这样的控件(虽然我已经有一段时间没有看过WPF控件供应商提供的所有控件了),但是创建这样的控件相对简单 您所要做的就是创建一个自定义控件,其中包含一个图像(或XAML图形),您可以旋转该图像以跟随鼠标。然后,将RotateTrans
我将如何创建其中一个?某个地方已经存在这样的控件了吗?我还没有见过这样的控件(虽然我已经有一段时间没有看过WPF控件供应商提供的所有控件了),但是创建这样的控件相对简单 您所要做的就是创建一个自定义控件,其中包含一个图像(或XAML图形),您可以旋转该图像以跟随鼠标。然后,将RotateTransform绑定到自定义控件上的“角度”从属属性,以便在更新“角度”时,图像/图形旋转以匹配:
<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>
将RenderTransferMorigin设置为“0.5,0.5”可确保控件围绕其中心旋转,而不是围绕左上角旋转;我们也必须在角度计算中对此进行补偿
在控件的代码隐藏文件中,添加鼠标和角度相关属性的处理程序:
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;
}
}
}
}
公共部分类VolumeControl:UserControl
{
//对角度使用DependencyProperty后台存储。
公共静态只读从属属性AngleProperty=
DependencyProperty.Register(“角度”、typeof(双精度)、typeof(VolumeControl)、新UIPropertyMetadata(0.0));
公共双角度
{
获取{return(double)GetValue(AngleProperty);}
set{SetValue(AngleProperty,value);}
}
公共卷控制()
{
初始化组件();
this.MouseLeftButtonDown+=新的MouseButtonEventHandler(OnMouseLeftButtonDown);
this.MouseUp+=新的MouseButtonEventHandler(OnMouseUp);
this.MouseMove+=新的MouseEventHandler(OnMouseMove);
}
MouseLeftButtonDown上的私有void(对象发送器,MouseButtonEventArgs e)
{
鼠标。捕捉(这个);
}
MouseUp上的私有void(对象发送器,鼠标按钮ventargs e)
{
鼠标捕捉(空);
}
MouseMove上的私有void(对象发送方,MouseEventArgs e)
{
if(Mouse.Captured==此)
{
//获取相对于音量控件的当前鼠标位置
Point currentLocation=Mouse.GetPosition(此);
//我们想绕着旋钮的中心旋转,而不是上角
点旋钮中心=新点(this.ActualHeight/2,this.ActualWidth/2);
//计算角度
双弧度=Math.Atan((currentLocation.Y-knobCenter.Y)/
(currentLocation.X-knobCenter.X));
角度=弧度*180/Math.PI;
//当X为负时,应用180度移动,以便我们可以旋转
//一路走来
if(currentLocation.X-knobCenter.X<0)
{
该角度+=180;
}
}
}
}
捕获鼠标可确保即使用户将鼠标从控件上移开(直到他们放开鼠标),并且通过获取鼠标相对于当前元素(控件)的位置,控件也会继续获得鼠标更新,无论控件在屏幕上的实际渲染位置如何,您的计算应该始终相同
在本例中,当鼠标移动时,我们计算鼠标与控件中心之间的角度,然后将该角度设置为我们创建的角度相关属性。由于我们正在显示的图像绑定到这个角度属性,WPF会自动应用新值,这会导致旋钮随着鼠标移动而旋转
在解决方案中使用控件很容易;只需添加:
<local:VolumeControl />
如果希望将旋钮的值绑定到应用程序中的某个内容,则可以绑定到VolumeControl上的Angle属性;该值当前以度为单位,但可以添加一个附加属性,以便在以度为单位的角度和对您有意义的值(例如,从0到10的值)之间进行转换。要添加到该贴子,鼠标点和对象点之间的角度计算如下:
dot = currentLocation.X * objectPosition.X + currentLocation.Y * objectPosition.Y;
angle = Math.Acos(dot);
在我的例子中,我已经动态地创建了一些形状,这些形状将朝着鼠标方向旋转。为了解决这个问题,我使用了一个轻量级函数。我只需要以下几点:
- 当前选定形状的中心点
- 最后一个鼠标悬停步骤中的点
- 以及当前鼠标悬停步骤中的点
private void HandleLeftMouseDown(MouseButtonEventArgs eventargs)
{
//Calculate the center point of selected object
//...
//assuming Point1 is the top left point
var xCenter = (_selectedObject.Point2.X - _selectedObject.Point1.X) / 2 + _selectedObject.Point1.X
var yCenter = (_selectedObject.Point2.Y - _selectedObject.Point1.Y) / 2 + _selectedObject.Point1.Y
_selectedObjectCenterPoint = new Point((double) xCenter, (double) yCenter);
//init set of last mouse over step with the mouse click point
var clickPoint = eventargs.GetPosition(source);
_lastMouseOverPoint = new Point(clickPoint.X,clickPoint.Y);
}
private void HandleMouseMove(MouseEventArgs eventArgs)
{
Point pointMouseOver = eventArgs.GetPosition(_source);
//Get the difference to the last mouse over point
var xd = pointMouseOver.X - _lastMouseOverPoint.X;
var yd = pointMouseOver.Y - _lastMouseOverPoint.Y;
// the direction depends on the current mouse over position in relation to the center point of the shape
if (pointMouseOver.X < _selectedObjectCenterPoint.X)
yd *= -1;
if (pointMouseOver.Y > _selectedObjectCenterPoint.Y)
xd *= -1;
//add to the existing Angle
//not necessary to calculate the degree measure
_selectedObject.Angle += (xd + yd);
//save mouse over point
_lastMouseOverPoint = new Point(pointMouseOver.X, pointMouseOver.Y);
}
private void HandleLeftMouseDown(鼠标按钮ventargs事件参数)
{
//计算选定对象的中心点
//...
//假设点1是左上角的点
var xCenter=(_selectedObject.Point2.X-_selectedObject.Point1.X)/2+_selectedObject.Point1.X
变量yCenter=(_selectedObject.Point2.Y-_selectedObject.Point1.Y)/2+_selectedObject.Point1.Y
_选择对象中心点=新点((双)X中心,(双)Y中心);
//用鼠标点击点初始化最后一步的鼠标集
var clickPoint=eventargs.GetPosition(源);
_lastMouseOverPoint=新点(clickPoint.X,clickPoint.Y);
}
私有void HandleMouseMove(MouseEventArgs eventArgs)
{
Point pointMouseOver=eventArgs.GetPosition(_source);
//获得鼠标在最后一点上的差值
var xd=pointMouseOver.X-\u lastMouseOverPoint.X;
var yd=鼠标指针在.Y-\u lastMo上