Search code examples
xamlwindows-runtimewindows-store-appswinrt-xaml

Custom Slider Windows 8.1


i need to create a custom slider, at the moment my slider looks exactly how i want, it looks like this (image from VisualStudio):

enter image description here ant the xaml code is this:

<Grid x:Name="mainGrid">
    <Grid Height="240" Width="300" Canvas.ZIndex="2">
        <Grid.RenderTransform>
            <RotateTransform x:Name="rotateTransform" 
                             Angle="-125" 
                             CenterX="150" 
                             CenterY="150" />
        </Grid.RenderTransform>

        <Ellipse Height="54" Width="54" 
                 x:Name="knob"
                 Fill="Red"
                 PointerMoved="Image_PointerMoved" 
                 VerticalAlignment="Top" 
                 Margin="0,-7,0,0"/>
    </Grid>

    <Path x:Name="path"
          Data="M269.01,233.229 C303.532,181.303 304.261,118.855 269.097,67.0139 C207.933,-15.2077 92.8603,-16.8742 31.2108,66.0937 C-3.68835,121.514 -3.36331,179.271 30.8461,232.917 C51.2571,253.282 74.8965,230.573 61.3585,209.167 C38.2919,172.761 36.0008,129.688 62.1396,90.2093 C106.398,28.022 194.916,29.4803 237.509,90.1399 C262.554,127.345 263.613,170.209 237.647,209.792 C227.355,233.49 250.474,250.782 269.01,233.229 z" 
          Stretch="Fill"  
          Fill="Gray" />

</Grid>

and the C# code is this:

private void Image_PointerMoved(object sender, PointerRoutedEventArgs e)
    {
        //Canculate the current rotation angle and set the value.
        var newPos = e.GetCurrentPoint(path);
        double angle = GetAngleR(newPos.Position);

        rotateTransform.Angle = angle;
    }

    public double GetAngleR(Point pos)
    {
        var xDiff = 150 - pos.X;
        var yDiff = 150 - pos.Y;
        var r = Math.Sqrt((xDiff * xDiff) + (yDiff * yDiff));

        var radians = Math.Acos((yDiff) / r);

        var angle = radians * (180 / Math.PI);

        if(angle > 125)
        {
            angle = 125;
        }

        if(pos.X < 150)
        {
            angle = -angle;
        }

        return angle;
    }

my problem is how i fill the path with a different color as i move the ellipse?

i need to achive somethig like this:

enter image description here

any suggestion?


Solution

  • Ok I have figured out how to do this slider, this isn't a perfect solution but it works and for me is enough.

    I have created a GeometryGroup that contains some BezierSegment used to draw the arch path and then I have added a to the group a RectangleGeometry that is the size of the element.

    With GeometryGroup in this case, the intersecting area of two shapes is not filled.

    After that i have placed the right color behind the main path.

    this is the code:

    XAML

    <Grid x:Name="mainGrid">
        <Grid Height="240" Width="300" Canvas.ZIndex="2">
            <Grid.RenderTransform>
                <RotateTransform x:Name="rotateTransform" 
                                 Angle="-125" 
                                 CenterX="150" 
                                 CenterY="150" />
            </Grid.RenderTransform>
    
            <Image Height="54" Width="54" x:Name="knob"
                   Source="ms-appx:///Assets/ic_slider_credito.png" 
                   PointerMoved="Image_PointerMoved" 
                   VerticalAlignment="Top" 
                   Margin="0,-5,0,0" />
        </Grid>
    
        <Rectangle VerticalAlignment="Top" 
                   HorizontalAlignment="Left"
                   Fill="Gray" 
                   Width="300" 
                   Height="240" />
    
        <Path x:Name="fillPath" 
              Height="240"
              Width="300"
              UseLayoutRounding="False"
              VerticalAlignment="Top" 
              HorizontalAlignment="Left"
              Fill="Orange" />
    
        <Path x:Name="path" 
              Height="240"
              Width="300"
              UseLayoutRounding="False"
              Stretch="Fill"  
              Fill="White" />
    </Grid>
    

    C#

        public SliderInvioCredito()
        {
            this.InitializeComponent();
            DrawPath();
        }
    
        private void Image_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            var newPos = e.GetCurrentPoint(path);
            double angle = GetAngleR(newPos.Position);
    
            rotateTransform.Angle = angle;
        }
    
        public double GetAngleR(Point pos)
        {
            var xDiff = 150 - pos.X;
            var yDiff = 150 - pos.Y;
            var r = Math.Sqrt((xDiff * xDiff) + (yDiff * yDiff));
    
            var radians = Math.Acos((yDiff) / r);
    
            var angle = radians * (180 / Math.PI);
    
            if (angle > 125)
            {
                angle = 125;
            }
    
            if (pos.X < 150)
            {
                angle = -angle;
            }
    
            DrawFillPath(pos.X, pos.Y, angle);
    
            return angle;
        }
    
        private void DrawFillPath(double x, double y, double angle)
        {
            var start = new Point(150, 120);
            var pth = new PathFigure();
            pth.StartPoint = start;
    
            var ls1 = new LineSegment();
            ls1.Point = start;
            pth.Segments.Add(ls1);
    
            var ls8 = new LineSegment();
            ls8.Point = new Point(150, 240);
            pth.Segments.Add(ls8);
    
            var ls2 = new LineSegment();
            ls2.Point = new Point(0, 240);
            pth.Segments.Add(ls2);
    
            if (angle > -45)
            {
                var ls5 = new LineSegment();
                ls5.Point = new Point(0, 0);
                pth.Segments.Add(ls5);
    
                if (angle > -30)
                {
                    var ls6 = new LineSegment();
                    ls6.Point = new Point(x, 0);
                    pth.Segments.Add(ls6);
                }
            }
            else
            {
                var ls3 = new LineSegment();
                ls3.Point = new Point(0, y);
                pth.Segments.Add(ls3);
            }
    
            if (angle > 45)
            {
                var ls7 = new LineSegment();
                ls7.Point = new Point(300, 0);
                pth.Segments.Add(ls7);
    
                var ls9 = new LineSegment();
                ls9.Point = new Point(300, y);
                pth.Segments.Add(ls9);
            }
    
            var ls4 = new LineSegment();
            ls4.Point = new Point(x, y);
            pth.Segments.Add(ls4);
    
            var pthCollection = new PathFigureCollection();
            pthCollection.Add(pth);
    
            var pthGeometry = new PathGeometry();
            pthGeometry.Figures = pthCollection;
    
            fillPath.Data = pthGeometry;
        }
    
        private void DrawPath()
        {
            var cc1 = new BezierSegment();
            cc1.Point1 = new Point(303.532, 181.303);
            cc1.Point2 = new Point(304.261, 118.855);
            cc1.Point3 = new Point(269.097, 67.0139);
    
            var cc2 = new BezierSegment();
            cc2.Point1 = new Point(207.933, -15.2077);
            cc2.Point2 = new Point(92.8603, -16.8742);
            cc2.Point3 = new Point(31.2108, 66.0937);
    
            var cc3 = new BezierSegment();
            cc3.Point1 = new Point(-3.68835, 121.514);
            cc3.Point2 = new Point(-3.36331, 179.271);
            cc3.Point3 = new Point(30.8461, 232.917);
    
            var cc4 = new BezierSegment();
            cc4.Point1 = new Point(51.2571, 253.282);
            cc4.Point2 = new Point(74.8965, 230.573);
            cc4.Point3 = new Point(61.3585, 209.167);
    
            var cc5 = new BezierSegment();
            cc5.Point1 = new Point(38.2919, 172.761);
            cc5.Point2 = new Point(36.0008, 129.688);
            cc5.Point3 = new Point(62.1396, 90.2093);
    
            var cc6 = new BezierSegment();
            cc6.Point1 = new Point(106.398, 28.022);
            cc6.Point2 = new Point(194.916, 29.4803);
            cc6.Point3 = new Point(237.509, 90.1399);
    
            var cc7 = new BezierSegment();
            cc7.Point1 = new Point(262.554, 127.345);
            cc7.Point2 = new Point(263.613, 170.209);
            cc7.Point3 = new Point(237.647, 209.792);
    
            var cc8 = new BezierSegment();
            cc8.Point1 = new Point(227.355, 233.49);
            cc8.Point2 = new Point(250.474, 250.782);
            cc8.Point3 = new Point(269.01, 233.229);
    
            var pthFigure = new PathFigure();
            pthFigure.StartPoint = new Point(269.01, 233.229);
    
            var psc = new PathSegmentCollection();
            psc.Add(cc1);
            psc.Add(cc2);
            psc.Add(cc3);
            psc.Add(cc4);
            psc.Add(cc5);
            psc.Add(cc6);
            psc.Add(cc7);
            psc.Add(cc8);
    
            pthFigure.Segments = psc;
    
            var pthFigureCollection = new PathFigureCollection();
            pthFigureCollection.Add(pthFigure);
    
            var pthGeometry = new PathGeometry();
            pthGeometry.Figures = pthFigureCollection;
    
            var rect = new RectangleGeometry();
            rect.Rect = new Rect(0, 0, 300, 240);
    
            var gg = new GeometryGroup();
            gg.Children.Add(pthGeometry);
            gg.Children.Add(rect);
    
            path.Data = gg;
        }