wpf做的标尺

wpf是微软下一代的window开发平台,或者说是xaml,毕竟c++以后也支持了,在想directUI这种东西以后还会有人用吗?

因为我主要负责的是编辑器的工作,所以需要做一个标尺,下面先看下我做的效果吧


提供三个属性
DisplayPercent 当前显示比例
DisplayType  显示方式 横向/竖向
ZeroPoint 选择0点位置

可选属性
Dpi
用于确定系统目前的Dpi,来让像素转换为cm
目前还不支持Cm/Pixel切换
现在只支持Pixel的显示

代码比较少,直接文章里上,欢迎大家使用,转载的话希望注明出处,谢谢了哈wpf做的标尺,【顺便分享代码一枚】 - 转载注明出处 gsralex.blog.163.com

 

 

/*
 * ///////////////////////////////////////
 * ///////////////////////////////////////
 * ///////////////////////////////////////
 * 转载注明出处 gsralex.blog.163.com//
 * ///////////////////////////////////////
 * ///////////////////////////////////////
 * ///////////////////////////////////////
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Globalization;

namespace GsrAlex
{
    public class GsrAlexStaff : Control
    {
        public static readonly DependencyProperty    DpiProperty        = DependencyProperty.Register( "Dpi", typeof(Dpi), typeof(GsrAlexStaff) );
        public static readonly DependencyProperty    DisplayPercentProperty    = DependencyProperty.Register( "DisplayPercent", typeof(double), typeof(GsrAlexStaff) );
        public static readonly DependencyProperty    DisplayTypeProperty    = DependencyProperty.Register( "DisplayType", typeof(StaffDisplayType), typeof(GsrAlexStaff) );
        public static readonly DependencyProperty    DisplayUnitProperty    = DependencyProperty.Register( "DisplayUnit", typeof(StaffDisplayUnit), typeof(GsrAlexStaff) );
        public static readonly DependencyProperty    ZeroPointProperty    = DependencyProperty.Register( "ZeroPoint", typeof(double), typeof(GsrAlexStaff) );

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


        #region 属性

/*
 * / <summary>
 * / Dpi
 * / </summary>
 */
        public Dpi Dpi
        {
            get
            {
                return( (Dpi) GetValue( DpiProperty ) );
            }
            set
            {
                SetValue( DpiProperty, value );
            }
        }

        public double ZeroPoint
        {
            get
            {
                return( (double) GetValue( ZeroPointProperty ) );
            }
            set
            {
                SetValue( ZeroPointProperty, value );
                InvalidateVisual();
            }
        }

/*
 * / <summary>
 * / 显示比例
 * / </summary>
 */
        public double DisplayPercent
        {
            get
            {
                return( (double) GetValue( DisplayPercentProperty ) );
            }
            set
            {
                SetValue( DisplayPercentProperty, value );
            }
        }

/*
 * / <summary>
 * / 显示类型
 * / </summary>
 */
        public StaffDisplayType DisplayType
        {
            get
            {
                return( (StaffDisplayType) GetValue( DisplayTypeProperty ) );
            }
            set
            {
                SetValue( DisplayTypeProperty, value );
            }
        }

/*
 * / <summary>
 * / 显示单位
 * / </summary>
 */
        public StaffDisplayUnit DisplayUnit
        {
            get
            {
                return( (StaffDisplayUnit) GetValue( DisplayUnitProperty ) );
            }
            set
            {
                SetValue( DisplayUnitProperty, value );
            }
        }


        #endregion

        #region 常量

        public const double    _inchCm            = 2.54;
        private const int    _p100StepSpanPixel    = 100;
        private const int    _p100StepSpanCm        = 2;
        private const int    _p100StepCountPixel    = 20;
        private const int    _p100StepCountCm    = 20;

        #endregion

        #region 变量

/*
 * / <summary>
 * / 1cm显示的像素数除以步进跨度的系数
 * / </summary>
 */
        private double _minRatio;
/*
 * / <summary>
 * / 1cm显示的像素数除以步进跨度的系数
 * / </summary>
 */
        private double _maxRatio;

        private double _minStepLengthCm;

        private double _maxStepLengthCm;

        private double        _actualLength;
        private int        _stepSpan;
        private int        _stepCount;
        private double        _stepLength;
        private bool        _isInvalidateVisual;
        private Point        _lastPoint;
        private Position    _lastPosition;


        #endregion


        protected override void OnRender( DrawingContext drawingContext )
        {
            try
            {
                Pen pen = new Pen( new SolidColorBrush( Colors.Black ), 0.5d );
                pen.Freeze();

                base.OnRender( drawingContext );

                Initialize();
                GetStep();
                GetActualLength();

                this.BorderBrush    = new SolidColorBrush( Colors.Black );
                this.BorderThickness    = new Thickness( 0.5 );
/* this.Background = new SolidColorBrush(Colors.White); */


                #region try

                double actualPx = this._actualLength / DisplayPercent;


                Position currentPosition = new Position {
                    CurrentStepIndex = 0, Value = 0
                };

                switch ( DisplayType )
                {
                case StaffDisplayType.Horizontal:
                {
/* 绘制前半段 */
                    DrawLine( drawingContext, ZeroPoint, currentPosition, pen, 0 );
/* 绘制后半段 */
                    DrawLine( drawingContext, ZeroPoint, currentPosition, pen, 1 );


                    break;
                }
                case StaffDisplayType.Vertical:
                {
/* 绘制前半段 */
                    DrawLine( drawingContext, ZeroPoint, currentPosition, pen, 0 );
/* 绘制后半段 */
                    DrawLine( drawingContext, ZeroPoint, currentPosition, pen, 1 );

                    break;
                }
                }


                #endregion
            }
            catch ( Exception ex )
            {
                Console.WriteLine( ex.Message );
            }
        }


        private void DrawLine( DrawingContext drawingContext, double currentPoint, Position currentPosition, Pen pen, int type )
        {
            double linePercent = 0d;

            while ( true )
            {
                if ( currentPosition.CurrentStepIndex == 0 )
                {
                    linePercent = (int) LinePercent.P100;
                    FormattedText formattedText = GetFormattedText( currentPosition.Value.ToString() );

                    switch ( DisplayType )
                    {
                    case StaffDisplayType.Horizontal:
                    {
                        drawingContext.DrawText( formattedText, new Point( currentPoint + formattedText.Width / 2, formattedText.Height / 3 ) );
                        break;
                    }
                    case StaffDisplayType.Vertical:
                    {
                        Point        point        = new Point( this.ActualWidth, currentPoint + formattedText.Height / 2 );
                        RotateTransform rotateTransform = new RotateTransform( 90, point.X, point.Y );
                        drawingContext.PushTransform( rotateTransform );
                        drawingContext.DrawText( formattedText, point );
                        drawingContext.Pop();
                        break;
                    }
                    }


                    linePercent = (int) LinePercent.P100;
                }else if ( IsFinalNum( currentPosition.CurrentStepIndex, 3 ) )
                {
                    linePercent = (int) LinePercent.P30;
                }else if ( IsFinalNum( currentPosition.CurrentStepIndex, 5 ) )
                {
                    linePercent = (int) LinePercent.P50;
                }else if ( IsFinalNum( currentPosition.CurrentStepIndex, 7 ) )
                {
                    linePercent = (int) LinePercent.P30;
                }else if ( IsFinalNum( currentPosition.CurrentStepIndex, 0 ) )
                {
                    linePercent = (int) LinePercent.P70;
                }else  {
                    linePercent = (int) LinePercent.P20;
                }

                linePercent = linePercent * 0.01;

                if ( linePercent == 1 )
                {
                }


                switch ( DisplayType )
                {
                case StaffDisplayType.Horizontal:
                {
                    drawingContext.DrawLine( pen, new Point( currentPoint, 0 ), new Point( currentPoint, this.ActualHeight * linePercent ) );

                    if ( type == 0 )
                    {
                        currentPoint = currentPoint - _stepLength;
                        currentPosition.CurrentStepIndex--;

                        if ( currentPosition.CurrentStepIndex < 0 )
                        {
                            currentPosition.CurrentStepIndex    = _stepCount - 1;
                            currentPosition.Value            = GetNextStepValue( currentPosition.Value, _stepSpan, 0 );
                        }else if ( currentPosition.CurrentStepIndex == 0 )
                        {
                            if ( currentPosition.Value % _stepSpan != 0 )
                                currentPosition.Value = GetNextStepValue( currentPosition.Value, _stepSpan, 0 );
                        }

                        if ( currentPoint <= 0 )
                        {
                            return;
                        }
                    }else  {
                        currentPoint = currentPoint + _stepLength;
                        currentPosition.CurrentStepIndex++;

                        if ( currentPosition.CurrentStepIndex >= _stepCount )
                        {
                            currentPosition.CurrentStepIndex    = 0;
                            currentPosition.Value            = GetNextStepValue( currentPosition.Value, _stepSpan, 1 );
                        }

                        if ( currentPoint >= _actualLength )
                        {
                            return;
                        }
                    }
                    break;
                }
                case StaffDisplayType.Vertical:
                {
                    drawingContext.DrawLine( pen, new Point( 0, currentPoint ), new Point( this.ActualWidth * linePercent, currentPoint ) );

                    if ( type == 0 )
                    {
                        currentPoint = currentPoint - _stepLength;
                        currentPosition.CurrentStepIndex--;

                        if ( currentPosition.CurrentStepIndex < 0 )
                        {
                            currentPosition.CurrentStepIndex    = _stepCount - 1;
                            currentPosition.Value            = GetNextStepValue( currentPosition.Value, _stepSpan, 0 );
                        }else if ( currentPosition.CurrentStepIndex == 0 )
                        {
                            if ( currentPosition.Value % _stepSpan != 0 )
                                currentPosition.Value = GetNextStepValue( currentPosition.Value, _stepSpan, 0 );
                        }

                        if ( currentPoint <= 0 )
                        {
                            return;
                        }
                    }else  {
                        currentPoint = currentPoint + _stepLength;
                        currentPosition.CurrentStepIndex++;

                        if ( currentPosition.CurrentStepIndex >= _stepCount )
                        {
                            currentPosition.CurrentStepIndex    = 0;
                            currentPosition.Value            = GetNextStepValue( currentPosition.Value, _stepSpan, 1 );
                        }

                        if ( currentPoint >= _actualLength )
                        {
                            return;
                        }
                    }
                    break;
                }
                }
            }
        }


        private int GetNextStepValue( int value, int times, int type )
        {
            if ( type == 0 )
            {
                do
                {
                    value--;
                }
                while ( value % times != 0 );
            }else  {
                do
                {
                    value++;
                }
                while ( value % times != 0 );
            }


            return(value);
        }


        private FormattedText GetFormattedText( string text )
        {
            return(new FormattedText( text,
                          CultureInfo.GetCultureInfo( "zh-cn" ),
                          FlowDirection.LeftToRight,
                          new Typeface( "Microsoft YaHei" ),
                          8,
                          Brushes.Black ) );
        }


        private bool IsFinalNum( int value, int finalNum )
        {
            string valueStr = value.ToString();
            if ( valueStr.Substring( valueStr.Length - 1, 1 ) == finalNum.ToString() )
            {
                return(true);
            }
            return(false);
        }


        private void Initialize()
        {
            Dpi dpi = new Dpi();
            dpi.DpiX    = Dpi.DpiX;
            dpi.DpiY    = Dpi.DpiY;
            if ( Dpi.DpiX == 0 )
            {
                dpi.DpiX = 96;
            }

            if ( Dpi.DpiY == 0 )
            {
                dpi.DpiY = 96;
            }

            Dpi = dpi;

            _maxRatio = 1 / _inchCm * GetDpi() / 80;


            _minRatio = 1 / _inchCm * GetDpi() / 200;


            _minStepLengthCm    = 0.1;
            _maxStepLengthCm    = 0.3;


            if ( DisplayPercent == 0 )
                DisplayPercent = 1;


            switch ( DisplayUnit )
            {
            case StaffDisplayUnit.pixel:
            {
                _stepSpan    = _p100StepSpanPixel;
                _stepCount    = _p100StepCountPixel;
                break;
            }
            case StaffDisplayUnit.cm:
            {
                _stepSpan    = _p100StepSpanCm;
                _stepCount    = _p100StepCountCm;
                break;
            }
            }

            int width = 15;

            switch ( DisplayType )
            {
            case StaffDisplayType.Horizontal:
            {
                if ( this.ActualHeight == 0 )
                {
                    Height = width;
                }
                break;
            }
            case StaffDisplayType.Vertical:
            {
                if ( this.ActualWidth == 0 )
                {
                    Width = width;
                }
                break;
            }
            }
        }


        private void GetStep()
        {
            switch ( DisplayUnit )
            {
            case StaffDisplayUnit.pixel:
            {
/* 100px */
                _stepSpan    = 100;
                _stepCount    = 20;

/* 求出当前跨度应该显示的cm */
                double stepSpanCm = _stepSpan / Common.Utility.ConvertDouble( GetDpi() ) * _inchCm * DisplayPercent;


                while ( true )
                {
                    stepSpanCm = _stepSpan / Common.Utility.ConvertDouble( GetDpi() ) * _inchCm * DisplayPercent;
                    double    stepLengthCm    = stepSpanCm / _stepCount;
                    int    type        = 0;
                    bool    isOut        = false;
                    if ( stepLengthCm > _maxStepLengthCm )
                    {
                        type        = 1;
                        _stepCount    = GetNextStepCount( _stepCount, type, ref isOut );
                    }

                    if ( stepLengthCm < _minStepLengthCm )
                    {
                        type        = 0;
                        _stepCount    = GetNextStepCount( _stepCount, type, ref isOut );
                    }

                    if ( stepLengthCm <= _maxStepLengthCm && stepLengthCm >= _minStepLengthCm )
                    {
                        _stepLength = stepSpanCm / _inchCm * GetDpi() / _stepCount;


                        break;
                    }

/* 已超出或小于最大步进长度 */
                    if ( isOut )
                    {
                        _stepSpan = GetNextStepSpan( _stepSpan, type );
                        continue;
                    }
                }


                break;
            }
            }
        }


        private int GetNextStepCount( int stepCount, int type, ref bool isOut )
        {
            int result = stepCount;
            isOut = false;

            switch ( type )
            {
            case 0:
            {
                if ( stepCount == 20 )
                {
                    result = 10;
                }else  {
                    isOut = true;
                }
                break;
            }
            case 1:
            {
                if ( stepCount == 10 )
                {
                    result = 20;
                }else  {
                    isOut = true;
                }

                break;
            }
            }

            return(result);
        }


        private int GetNextStepSpan( int stepSpan, int type )
        {
/* 100 200 500 */
            string    stepCountStr    = stepSpan.ToString();
            string    resultStr    = string.Empty;

            switch ( DisplayUnit )
            {
            case StaffDisplayUnit.pixel:
            {
                switch ( type )
                {
                case 0:
                {
                    if ( stepCountStr.IndexOf( '5' ) > -1 )
                    {
                        resultStr = GetNumberAndZeroNum( 1, stepCountStr.Length );
                    }else if ( stepCountStr.IndexOf( '2' ) > -1 )
                    {
                        resultStr = GetNumberAndZeroNum( 5, stepCountStr.Length - 1 );
                    }else if ( stepCountStr.IndexOf( '1' ) > -1 )
                    {
                        resultStr = GetNumberAndZeroNum( 2, stepCountStr.Length - 1 );
                    }
                    break;
                }
                case 1:
                {
                    if ( stepCountStr.IndexOf( '5' ) > -1 )
                    {
                        resultStr = GetNumberAndZeroNum( 2, stepCountStr.Length - 1 );
                    }else if ( stepCountStr.IndexOf( '2' ) > -1 )
                    {
                        resultStr = GetNumberAndZeroNum( 1, stepCountStr.Length - 1 );
                    }else if ( stepCountStr.IndexOf( '1' ) > -1 )
                    {
                        resultStr = GetNumberAndZeroNum( 5, stepCountStr.Length - 2 );
                    }
                    break;
                }
                }

                break;
            }
            }

            return(Common.Utility.ConvertInt( resultStr ) );
        }


        private string GetNumberAndZeroNum( int num, int zeroNum )
        {
            string result = string.Empty;
            result += num;
            for ( int i = 0; i < zeroNum; i++ )
            {
                result += "0";
            }

            return(result);
        }


        private int GetDpi()
        {
            switch ( DisplayType )
            {
            case StaffDisplayType.Horizontal:
            {
                return(Dpi.DpiX);
            }
            case StaffDisplayType.Vertical:
            {
                return(Dpi.DpiY);
            }
            default:
            {
                return(Dpi.DpiX);
            }
            }
        }


        private void GetActualLength()
        {
            switch ( DisplayType )
            {
            case StaffDisplayType.Horizontal:
            {
                _actualLength = this.ActualWidth;
                break;
            }
            case StaffDisplayType.Vertical:
            {
                _actualLength = this.ActualHeight;
                break;
            }
            }
        }
    }


    public enum StaffDisplayType
    {
        Horizontal, Vertical
    }

    public enum StaffDisplayUnit
    {
        cm, pixel
    }

    public enum LinePercent
    {
        P20 = 20, P30 = 30, P50 = 50, P70 = 70, P100 = 100
    }

    public struct Dpi
    {
        public int DpiX {
            get; set;
        }
        public int DpiY {
            get; set;
        }
    }

    public struct Position
    {
        public int Value {
            get; set;
        }
        public int CurrentStepIndex {
            get; set;
        }
    }
}
 
 

2012年7月14 于郑州 天气:晴

posted @ 2012-07-14 17:09  gsralex  阅读(2104)  评论(1编辑  收藏  举报