我想创建看起来像这样的控件。所以我选择从 Selector 中派生出来,并将项目放置在 Canvas 上。这是一个问题:我应该如何对物品的放置进行编码?(也许为包含坐标的项目创建包装类,或者总是从 Canvas 接收坐标?)
PS 或者您可能只是将我发送到已经实施的类似控制(不幸的是,我没有找到任何)。
开始看这个example
。在此示例中包含 ControlTemplate 为Slider
.
例子:
XAML
<Window x:Class="SliderControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:SliderControl"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<my:ValueAngleConverter x:Key="valueAngleConverter"/>
<my:ValueTextConverter x:Key="valueTextConverter"/>
</Window.Resources>
<Grid>
<Slider Name="knob">
<Slider.Template>
<ControlTemplate>
<Viewbox>
<Canvas Width="300" Height="300" Margin="5">
<Ellipse Fill="LightBlue" Width="300" Height="300" Canvas.Left="0" Canvas.Top="0"
Stroke="Black" StrokeThickness="10" MouseLeftButtonUp="Ellipse_MouseLeftButtonUp"
MouseMove="Ellipse_MouseMove" />
<Ellipse Fill="Black" Width="60" Height="60" Canvas.Left="120" Canvas.Top="120" />
<Canvas>
<Line Stroke="Red" StrokeThickness="5"
X1="150" Y1="150" X2="150" Y2="10"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp" />
<Ellipse Fill="Red" Width="20" Height="20"
Canvas.Left="140" Canvas.Top="0"
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp">
<Ellipse.ToolTip>
<ToolTip>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value" Converter="{StaticResource valueTextConverter}"/>
</ToolTip>
</Ellipse.ToolTip>
</Ellipse>
<Canvas.RenderTransform>
<RotateTransform CenterX="150" CenterY="150">
<RotateTransform.Angle>
<MultiBinding Converter="{StaticResource valueAngleConverter}">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
</MultiBinding>
</RotateTransform.Angle>
</RotateTransform>
</Canvas.RenderTransform>
</Canvas>
</Canvas>
</Viewbox>
</ControlTemplate>
</Slider.Template>
</Slider>
</Grid>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private bool _isPressed = false;
private Canvas _templateCanvas = null;
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//Enable moving mouse to change the value.
_isPressed = true;
}
private void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//Disable moving mouse to change the value.
_isPressed = false;
}
private void Ellipse_MouseMove(object sender, MouseEventArgs e)
{
if (_isPressed)
{
//Find the parent canvas.
if (_templateCanvas == null)
{
_templateCanvas = MyHelper.FindParent<Canvas>(e.Source as Ellipse);
if (_templateCanvas == null) return;
}
//Canculate the current rotation angle and set the value.
const double RADIUS = 150;
Point newPos = e.GetPosition(_templateCanvas);
double angle = MyHelper.GetAngleR(newPos, RADIUS);
knob.Value = (knob.Maximum - knob.Minimum) * angle / (2 * Math.PI);
}
}
}
//The converter used to convert the value to the rotation angle.
public class ValueAngleConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
double value = (double)values[0];
double minimum = (double)values[1];
double maximum = (double)values[2];
return MyHelper.GetAngle(value, maximum, minimum);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
//Convert the value to text.
public class ValueTextConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
double v = (double)value;
return String.Format("{0:F2}", v);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
public static class MyHelper
{
//Get the parent of an item.
public static T FindParent<T>(FrameworkElement current)
where T : FrameworkElement
{
do
{
current = VisualTreeHelper.GetParent(current) as FrameworkElement;
if (current is T)
{
return (T)current;
}
}
while (current != null);
return null;
}
//Get the rotation angle from the value
public static double GetAngle(double value, double maximum, double minimum)
{
double current = (value / (maximum - minimum)) * 360;
if (current == 360)
current = 359.999;
return current;
}
//Get the rotation angle from the position of the mouse
public static double GetAngleR(Point pos, double radius)
{
//Calculate out the distance(r) between the center and the position
Point center = new Point(radius, radius);
double xDiff = center.X - pos.X;
double yDiff = center.Y - pos.Y;
double r = Math.Sqrt(xDiff * xDiff + yDiff * yDiff);
//Calculate the angle
double angle = Math.Acos((center.Y - pos.Y) / r);
Console.WriteLine("r:{0},y:{1},angle:{2}.", r, pos.Y, angle);
if (pos.X < radius)
angle = 2 * Math.PI - angle;
if (Double.IsNaN(angle))
return 0.0;
else
return angle;
}
}
样品屏幕: