2013-04-22 100 views
1

我想創建看起來像this的控件。所以我選擇從Selector派生它並將其放置在Canvas上。 這裏是一個問題:我應該如何編碼項目的編碼? (可能會爲包含座標的項目創建包裝類,或者只是始終從Canvas接收座標?)創建自定義選擇器(多開關)/ WPF C#

P.S.或者你可能只是發送我已經實施類似的控制(不幸的是,我沒有找到任何)。

回答

0

請參見此example開始。在此示例中包含用於Slider的ControlTemplate。

實施例:

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; 
    } 
} 

樣品的屏幕:

enter image description here

+0

感謝您的幫助,但您沒有得到我。我想創建不滑塊,但項目控制(我的意思是不能只有數字,但也可以是文字/其他控件) – 2013-04-23 12:14:01

+1

你可以把元素放在滑塊周圍嗎?每個元素對應的數字。例如:如果滑塊值數字1 - 用戶選擇按鈕1,數字2 - 按鈕2等 – 2013-04-23 12:34:58