Я не видел ни одного подобного элемента управления (хотя я давно изучал все элементы управления, предлагаемые поставщиками элементов управления WPF), но создать его довольно просто.
Все, что вам нужно сделать, это создать собственный элемент управления, содержащий изображение (или чертеж XAML), который вы можете вращать, следуя за мышью. Затем привяжите RotateTransform к свойству DependencyProperty «Angle» в вашем пользовательском элементе управления, чтобы при обновлении «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;
}
}
}
}
Захват мыши гарантирует, что ваш элемент управления продолжит получать обновления мыши, даже когда пользователь отключается от элемента управления (пока он не отпустит щелчок), и путем определения положения мыши относительно текущего элемента ( control), ваши расчеты всегда должны быть одинаковыми независимо от того, где элемент управления отображается на экране.
В этом примере, когда мышь перемещается, мы вычисляем угол между ней и центром элемента управления, а затем устанавливаем этот угол равным Angle DependencyProperty, который мы создали. Поскольку изображение, которое мы показываем, привязано к этому свойству угла, WPF автоматически применяет новое значение, что приводит к вращению ручки в сочетании с движением мыши.
Использовать элемент управления в вашем решении легко; просто добавьте:
<local:VolumeControl />
Вы бы привязали к свойству Angle на VolumeControl, если бы вы хотели привязать значение ручки к чему-либо в вашем приложении; это значение в настоящее время в градусах, но может добавить дополнительное свойство для преобразования между углом в градусах и значением, которое имеет смысл для вас (скажем, значение от 0 до 10).