【问题标题】:Creating custom Selector (multi switch) / WPF C#创建自定义选择器(多开关)/ WPF C#
【发布时间】:2013-04-22 09:39:46
【问题描述】:

我想创建看起来像this 的控件。所以我选择从 Selector 中派生出来,并将项目放置在 Canvas 上。 这是一个问题:我应该如何编码物品的放置? (也许为包含坐标的项目创建包装类,或者总是从 Canvas 接收坐标?)

附:或者您可以直接将我发送到已经实施的类似控制(不幸的是,我没有找到任何)。

【问题讨论】:

    标签: wpf controls selector


    【解决方案1】:

    请参阅此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;
        }
    }
    

    示例屏幕:

    【讨论】:

    • 感谢您的帮助,但您没有得到我的帮助。我想创建的不是滑块,而是项目控件(我的意思是不仅可以有数字,还可以有文字/其他控件)
    • 你能把元素放在滑块周围吗?每个元素对应一个数字。例如:如果滑块值数字 1 - 用户选择按钮 1,数字 2 - 按钮 2,等等。
    猜你喜欢
    • 2012-08-25
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2017-01-21
    • 2012-01-22
    相关资源
    最近更新 更多