仿Word的支持横轴竖轴的WPF 标尺
Posted wuty007
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仿Word的支持横轴竖轴的WPF 标尺相关的知识,希望对你有一定的参考价值。
最近在 https://mp.weixin.qq.com/s/3dEO0NZQv5YLqK72atG4Wg 官方公众号看到了 用WPF 制作 标尺
在去年项目上也接到了一个需求,用于排版自定义拖拽控件画布对齐的标尺,当时接到的要求是 需要横纵对齐的表次,并且鼠标滑动,刻度的上方需要跟着有影子划过的效果。
具体实现如下:
创建 标尺控件 RulerControl.cs
[TemplatePart(Name = "trackLine", Type = typeof(Line))] internal class RulerControl : Control { public static readonly DependencyProperty DpiProperty = DependencyProperty.Register("Dpi", typeof(Dpi), typeof(RulerControl)); public static readonly DependencyProperty DisplayPercentProperty = DependencyProperty.Register("DisplayPercent", typeof(double), typeof(RulerControl)); public static readonly DependencyProperty DisplayTypeProperty = DependencyProperty.Register("DisplayType", typeof(RulerDisplayType), typeof(RulerControl)); public static readonly DependencyProperty DisplayUnitProperty = DependencyProperty.Register("DisplayUnit", typeof(RulerDisplayUnit), typeof(RulerControl)); public static readonly DependencyProperty ZeroPointProperty = DependencyProperty.Register("ZeroPoint", typeof(double), typeof(RulerControl)); /// <summary> /// 定义静态构造函数 /// </summary> static RulerControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(RulerControl), new FrameworkPropertyMetadata(typeof(RulerControl))); } #region 属性 /// <summary> /// 屏幕分辨率 /// </summary> public Dpi Dpi { get { return ((Dpi)GetValue(DpiProperty)); } set { SetValue(DpiProperty, value); } } /// <summary> /// 设置0点从哪里开始 /// </summary> public double ZeroPoint { get { return ((double)GetValue(ZeroPointProperty)); } set { SetValue(ZeroPointProperty, value); InvalidateVisual(); } } /// <summary> /// 显示的比率(目前支持0-1的选项) /// </summary> public double DisplayPercent { get { return ((double)GetValue(DisplayPercentProperty)); } set { if (value > 1) { value = 1; } SetValue(DisplayPercentProperty, value); InvalidateVisual(); } } /// <summary> /// 显示的类型:枚举类(支持横向或者竖向) /// </summary> public RulerDisplayType DisplayType { get { return ((RulerDisplayType)GetValue(DisplayTypeProperty)); } set { SetValue(DisplayTypeProperty, value); } } /// <summary> /// 显示的单位:cm和pixel /// </summary> public RulerDisplayUnit DisplayUnit { get { return ((RulerDisplayUnit)GetValue(DisplayUnitProperty)); } set { SetValue(DisplayUnitProperty, value); } } #endregion #region 常量 public const double _inchCm = 2.54; //一英寸为2.54cm private const int _p100StepSpanPixel = 100; private const int _p100StepSpanCm = 2; private const int _p100StepCountPixel = 20; private const int _p100StepCountCm = 20; #endregion #region 变量 private double _minStepLengthCm; private double _maxStepLengthCm; private double _actualLength; private int _stepSpan; private int _stepCount; private double _stepLength; Line mouseVerticalTrackLine; Line mouseHorizontalTrackLine; #endregion #region 标尺边框加指针显示 public void RaiseHorizontalRulerMoveEvent(MouseEventArgs e) { Point mousePoint = e.GetPosition(this); mouseHorizontalTrackLine.X1 = mouseHorizontalTrackLine.X2 = mousePoint.X; } public void RaiseVerticalRulerMoveEvent(MouseEventArgs e) { Point mousePoint = e.GetPosition(this); mouseVerticalTrackLine.Y1 = mouseVerticalTrackLine.Y2 = mousePoint.Y; } public override void OnApplyTemplate() { base.OnApplyTemplate(); mouseVerticalTrackLine = GetTemplateChild("verticalTrackLine") as Line; mouseHorizontalTrackLine = GetTemplateChild("horizontalTrackLine") as Line; mouseVerticalTrackLine.Visibility = Visibility.Visible; mouseHorizontalTrackLine.Visibility = Visibility.Visible; } #endregion /// <summary> /// 重画标尺数据 /// </summary> /// <param name="drawingContext"></param> protected override void OnRender(DrawingContext drawingContext) { try { Pen pen = new Pen(new SolidColorBrush(Colors.Black),0.8d); pen.Freeze(); Initialize(); GetActualLength(); GetStep(); base.OnRender(drawingContext); this.BorderBrush = new SolidColorBrush(Colors.Black); this.BorderThickness = new Thickness(0.1); this.Background = new SolidColorBrush(Colors.White); #region try // double actualPx = this._actualLength / DisplayPercent; Position currentPosition = new Position { CurrentStepIndex = 0, Value = 0 }; switch (DisplayType) { case RulerDisplayType.Horizontal: { /* 绘制前半段 */ DrawLine(drawingContext, ZeroPoint, currentPosition, pen, 0); /* 绘制后半段 */ DrawLine(drawingContext, ZeroPoint, currentPosition, pen, 1); break; } case RulerDisplayType.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) { FormattedText formattedText = GetFormattedText((currentPosition.Value / 10).ToString()); switch (DisplayType) { case RulerDisplayType.Horizontal: { var point = new Point(currentPoint + formattedText.Width / 2, formattedText.Height / 3); if (point.X<0) { break; } drawingContext.DrawText(formattedText, point); break; } case RulerDisplayType.Vertical: { Point point = new Point(this.ActualWidth, currentPoint + formattedText.Height / 2); RotateTransform rotateTransform = new RotateTransform(90, point.X, point.Y); if (point.Y<0) { break; } 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; switch (DisplayType) { case RulerDisplayType.Horizontal: { if (currentPoint > 0) { 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 RulerDisplayType.Vertical: { if (currentPoint > 0) { 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; } } } } /// <summary> /// 获取下一个步长值 /// </summary> /// <param name="value">起始值</param> /// <param name="times">跨度</param> /// <param name="type">半段类型,分为前半段、后半段</param> /// <returns></returns> 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); } [Obsolete] private FormattedText GetFormattedText(string text) { return (new FormattedText(text, //CultureInfo.GetCultureInfo("zh-cn"), CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, new Typeface("宋体"), 12, 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); } /// <summary> /// 初始化获取屏幕的DPI /// </summary> 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; _minStepLengthCm = 0.1; _maxStepLengthCm = 0.3; if (DisplayPercent == 0) DisplayPercent = 1; switch (DisplayUnit) { case RulerDisplayUnit.pixel: { _stepSpan = _p100StepSpanPixel; _stepCount = _p100StepCountPixel; break; } case RulerDisplayUnit.cm: { _stepSpan = _p100StepSpanCm; _stepCount = _p100StepCountCm; break; } } int width = 15; switch (DisplayType) { case RulerDisplayType.Horizontal: { if (this.ActualHeight == 0) { Height = width; } break; } case RulerDisplayType.Vertical: { if (this.ActualWidth == 0) { Width = width; } break; } } } /// <summary> /// 获取每一个数字间隔的跨度 /// </summary> private void GetStep() { switch (DisplayUnit) { case RulerDisplayUnit.pixel: { double stepSpanCm; while (true) { stepSpanCm = _stepSpan / Convert.ToDouble(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 * Convert.ToDouble(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) { 怎样将word标尺调出来?word标尺的使用技巧!