WPF ruler

Copy from WPFDeveloper

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows;
using System.Globalization;

namespace WpfApp142
{
    public class ScaleBase : RangeBase//Control
    {
        //public static readonly DependencyProperty MaximumProperty =
        //    DependencyProperty.Register("Maximum", typeof(double), typeof(ScaleBase), new UIPropertyMetadata(0.0, OnMaximumChanged));

        //private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        //{
        //    var ctrl = (ScaleBase)d;
        //    ctrl.OnMaximumChanged((double)e.OldValue, (double)e.NewValue);
        //}
        //protected virtual void OnMaximumChanged(double oldValue, double newValue)
        //{
        //}

        //public static readonly DependencyProperty MinimumProperty =
        //    DependencyProperty.Register("Minimum", typeof(double), typeof(ScaleBase), new UIPropertyMetadata(0.0, OnMinimumChanged));

        //private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        //{
        //    var ctrl = (ScaleBase)d;
        //    ctrl.OnMinimumChanged((double)e.OldValue, (double)e.NewValue);
        //}
        //protected virtual void OnMinimumChanged(double oldValue, double newValue)
        //{
        //}

        //public static readonly DependencyProperty ValueProperty =
        //    DependencyProperty.Register("Value", typeof(double), typeof(ScaleBase), new UIPropertyMetadata(0.0, OnValueChanged));

        //private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        //{
        //    var ctrl = (ScaleBase)d;
        //    ctrl.OnValueChanged((double)e.OldValue, (double)e.NewValue);
        //}
        //protected virtual void OnValueChanged(double oldValue, double newValue)
        //{
        //}

        public static readonly DependencyProperty IntervalProperty =
            DependencyProperty.Register("Interval", typeof(double), typeof(ScaleBase), new UIPropertyMetadata(0.0, OnIntervalChanged));
        private static void OnIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = (ScaleBase)d;
            ctrl.OnIntervalChanged((double)e.OldValue, (double)e.NewValue);
        }
        protected virtual void OnIntervalChanged(double oldValue, double newValue)
        {
        }

        public static readonly DependencyProperty GeometryProperty =
            DependencyProperty.Register("Geometry", typeof(Geometry), typeof(ScaleBase), new PropertyMetadata(null, OnGeometryChanged));
        private static void OnGeometryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = (ScaleBase)d;
            ctrl.OnGeometryChanged((Geometry)e.OldValue, (Geometry)e.NewValue);
        }
        protected virtual void OnGeometryChanged(Geometry oldValue, Geometry newValue)
        {
        }

        //public double Maximum
        //{
        //    get => (double)GetValue(MaximumProperty);
        //    set => SetValue(MaximumProperty, value);
        //}

        //public double Minimum
        //{
        //    get => (double)GetValue(MinimumProperty);
        //    set => SetValue(MinimumProperty, value);
        //}
        //public double Value
        //{
        //    get => (double)GetValue(ValueProperty);
        //    set => SetValue(ValueProperty, value);
        //}
        public double Interval
        {
            get => (double)GetValue(IntervalProperty);

            set => SetValue(IntervalProperty, value);
        }
        public Geometry Geometry
        {
            get => (Geometry)GetValue(GeometryProperty);
            set => SetValue(GeometryProperty, value);
        }
    }

    public static class DrawingContextHelper
    {
        public static BrushConverter BrushConverter = new BrushConverter();

        public static FormattedText GetFormattedText(string text, Brush color = null,
           FlowDirection flowDirection = FlowDirection.RightToLeft, double textSize = 12.0D,
           FontWeight fontWeight = default)
        {
            if (fontWeight == default)
            {
                fontWeight = FontWeights.Thin;
            }
                
            return new FormattedText(
                text,
                CultureInfo.CurrentCulture,
                flowDirection,
                new Typeface( new FontFamily(), FontStyles.Normal, fontWeight, FontStretches.Normal),
                textSize, color == null ? null : color,1.25)
            {
                MaxLineCount = 1,
                TextAlignment = TextAlignment.Justify,
                Trimming = TextTrimming.CharacterEllipsis
            };
        }
    }
}








using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows;

namespace WpfApp142
{
    public class Ruler : ScaleBase
    {
        public static readonly DependencyProperty SpanIntervalProperty =
            DependencyProperty.Register("SpanInterval", typeof(double), typeof(Ruler), new UIPropertyMetadata(5.0, OnSpanIntervalChanged));

        private static void OnSpanIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as Ruler;
            ctrl?.InvalidateVisual();
        }

        public static readonly DependencyProperty MiddleMaskProperty =
            DependencyProperty.Register("MiddleMask", typeof(int), typeof(Ruler), new UIPropertyMetadata(2, OnMiddleMaskChanged));

        private static void OnMiddleMaskChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as Ruler;
            ctrl?.InvalidateVisual();
        }

        static Ruler()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Ruler), new FrameworkPropertyMetadata(typeof(Ruler)));
        }

        public Ruler()
        {
            SetValue(MaximumProperty, 240.0);
            SetValue(MinimumProperty, 120.0);
            SetValue(IntervalProperty, 30.0);
            SetValue(GeometryProperty, Geometry.Parse(@"M 257,0 257,25 264,49 250,49 257,25"));
            Loaded += Ruler_Loaded;
        }

        protected override void OnValueChanged(double oldValue, double newValue)
        {
            PaintPath();
        }
        protected override void OnMaximumChanged(double oldValue, double newValue)
        {
            InvalidateVisual();
        }

        protected override void OnMinimumChanged(double oldValue, double newValue)
        {
            InvalidateVisual();
        }

        protected override void OnIntervalChanged(double oldValue, double newValue)
        {
            InvalidateVisual();
        }

        public double SpanInterval
        {
            get => (double)GetValue(SpanIntervalProperty);

            set => SetValue(SpanIntervalProperty, value);
        }

        public int MiddleMask
        {
            get => (int)GetValue(MiddleMaskProperty);

            set => SetValue(MiddleMaskProperty, value);
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            RenderOptions.SetEdgeMode(this, EdgeMode.Aliased);
            var nextLineValue = 0d;
            var one_Width = ActualWidth / ((Maximum - Minimum) / Interval);

            for (var i = 0; i <= (Maximum - Minimum) / Interval; i++)
            {
                var numberText = DrawingContextHelper.GetFormattedText((Minimum + i * Interval).ToString(),
                    (Brush)DrawingContextHelper.BrushConverter.ConvertFromString("#FFFFFF"), FlowDirection.LeftToRight,
                    10);
                drawingContext.DrawText(numberText, new Point(i * one_Width - 8, 0));
                drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.White), 1), new Point(i * one_Width, 25),
                    new Point(i * one_Width, ActualHeight - 2));
                var cnt = Interval / SpanInterval;
                for (var j = 1; j <= cnt; j++)
                    if (j % MiddleMask == 0)
                        drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.White), 1),
                            new Point(j * (one_Width / cnt) + nextLineValue, ActualHeight - 2),
                            new Point(j * (one_Width / cnt) + nextLineValue, ActualHeight - 10));
                    else
                        drawingContext.DrawLine(new Pen(new SolidColorBrush(Colors.White), 1),
                            new Point(j * (one_Width / cnt) + nextLineValue, ActualHeight - 2),
                            new Point(j * (one_Width / cnt) + nextLineValue, ActualHeight - 5));

                nextLineValue = i * one_Width;
            }
        }

        void Ruler_Loaded(object sender, RoutedEventArgs e)
        {
            PaintPath();
        }

        void PaintPath()
        {
            if (Parent == null)
                return;
            var d_Value = Value - Minimum;
            var one_Value = ActualWidth / (Maximum - Minimum);
            var x_Point = one_Value * d_Value + ((double)Parent.GetValue(ActualWidthProperty) - ActualWidth) / 2d;
            Geometry =
                Geometry.Parse($"M {x_Point},0 {x_Point},25 {x_Point + 7},49 {x_Point - 7},49 {x_Point},25");
        }
    }
}




//xaml
<Window x:Class="WpfApp142.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp142"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Slider
                x:Name="PART_Slider"
                IsSnapToTickEnabled="True"
                Maximum="210"
                Minimum="10"
                Value="40" />
        <TextBlock
                Margin="0,20"
                HorizontalAlignment="Center"
                IsHitTestVisible="False"
                Text="{Binding ElementName=PART_Ruler, Path=Value}" />

        <UniformGrid Rows="3">
            <Grid
                 Height="51"
                 Margin="40,0"
                 Background="Red">
                <Path
                    Data="{Binding ElementName=PART_Ruler, Path=Geometry, Mode=TwoWay}"
                    Fill="Yellow"
                    Stroke="Blue"
                    StrokeThickness="1" />
                <local:Ruler
                    x:Name="PART_Ruler"
                    Margin="40,0"
                    Interval="20"
                    Maximum="210"
                    Minimum="10"
                    Value="{Binding ElementName=PART_Slider, Path=Value, Mode=TwoWay}" />
            </Grid>
            <Grid
                Height="51"
                Margin="40,0"
                Background="Green">
                <Path
                    Data="{Binding ElementName=PART_Ruler1, Path=Geometry, Mode=TwoWay}"
                    Fill="Yellow"
                    Stroke="Blue"
                    StrokeThickness="1" />
                <local:Ruler
                 x:Name="PART_Ruler1"
                 Margin="40,0"
                 Interval="20"
                 Maximum="210"
                 Minimum="10"
                 Value="{Binding ElementName=PART_Slider, Path=Value, Mode=TwoWay}" />
            </Grid>
            <Grid
             Height="51"
             Margin="40,0"
             Background="Black">
                <Path
                 Data="{Binding ElementName=PART_Ruler2, Path=Geometry, Mode=TwoWay}"
                 Fill="Yellow"
                 Stroke="Blue"
                 StrokeThickness="1" />
                <local:Ruler
                 x:Name="PART_Ruler2"
                 Margin="40,0"
                 Interval="20"
                 Maximum="210"
                 Minimum="10"
                 Value="{Binding ElementName=PART_Slider, Path=Value, Mode=TwoWay}" />
            </Grid>
        </UniformGrid>
    </Grid>

</Window>
复制代码

 

 

 

 

 

 

 

 

 

 

 

posted @   FredGrit  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2020-01-19 C# aggregateexception flatten innerexceptions
点击右上角即可分享
微信分享提示