private static FormattedText GetFormattedText( double value, Brush textBrush, Typeface textTypeface, IDoubleToStringConverter valueConverter, object valueConverterParameter) { string text = (valueConverter == null) ? value.ToString(CultureInfo.CurrentCulture.NumberFormat) : valueConverter.Convert(value, valueConverterParameter); var formattedText = new FormattedText( text, CultureInfo.CurrentCulture, CultureInfo.CurrentCulture.TextInfo.IsRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight, textTypeface, 8, textBrush); return(formattedText); }
protected override void OnRender(DrawingContext dc) { bool eliminateOverlapping = EliminateOverlapping; double controlActualWidth = ActualWidth, controlActualHeight = ActualHeight; Contract.Assert(ActualWidth >= 0); var size = new Size(controlActualWidth, controlActualHeight); double min = Minimum, max = Maximum; double range = max - min; double logicalToPhysical = 1.0; double textPointShiftDirection = 0.0d; var startPoint = new Point(0d, 0d); var endPoint = new Point(0d, 0d); // Take Thumb size in to account double halfReservedSpace = ReservedSpace * 0.5; switch (Placement) { case TickBarPlacement.Top: if (DoubleUtil.GreaterThanOrClose(ReservedSpace, size.Width)) { return; } size.Width -= ReservedSpace; textPointShiftDirection = -1.0d; startPoint = new Point(halfReservedSpace, size.Height); endPoint = new Point(halfReservedSpace + size.Width, size.Height); logicalToPhysical = size.Width / range; break; case TickBarPlacement.Bottom: if (DoubleUtil.GreaterThanOrClose(ReservedSpace, size.Width)) { return; } size.Width -= ReservedSpace; textPointShiftDirection = 0.0d; startPoint = new Point(halfReservedSpace, 0d); endPoint = new Point(halfReservedSpace + size.Width, 0d); logicalToPhysical = size.Width / range; break; case TickBarPlacement.Left: if (DoubleUtil.GreaterThanOrClose(ReservedSpace, size.Height)) { return; } size.Height -= ReservedSpace; textPointShiftDirection = 1.0d; startPoint = new Point(size.Width, size.Height + halfReservedSpace); endPoint = new Point(size.Width, halfReservedSpace); logicalToPhysical = size.Height / range * -1; break; case TickBarPlacement.Right: if (DoubleUtil.GreaterThanOrClose(ReservedSpace, size.Height)) { return; } size.Height -= ReservedSpace; textPointShiftDirection = 0.0d; startPoint = new Point(0d, size.Height + halfReservedSpace); endPoint = new Point(0d, halfReservedSpace); logicalToPhysical = size.Height / range * -1; break; } // Invert direciton of the ticks bool isDirectionReversed = IsDirectionReversed; if (isDirectionReversed) { logicalToPhysical *= -1; // swap startPoint & endPoint Point pt = startPoint; startPoint = endPoint; endPoint = pt; } Brush textBrush = Fill; var pen = new Pen(textBrush, 1.0d); DoubleCollection ticks = Ticks; const double pointRadius = 1.0d; IDoubleToStringConverter valueConverter = ValueConverter; object valueConverterParameter = ValueConverterParameter; var textTypeface = new Typeface("Verdana"); double startSpace = StartLabelSpace, endSpace = EndLabelSpace; Contract.Assume(startSpace >= 0.0); Contract.Assume(endSpace >= 0.0); // Is it Vertical? if ((Placement == TickBarPlacement.Left) || (Placement == TickBarPlacement.Right)) { double prevTextEdge = isDirectionReversed ? (0.0 - startSpace) : (controlActualHeight + startSpace); double maxTextEdge = isDirectionReversed ? (controlActualHeight + endSpace) : (0.0 - endSpace); // Reduce tick interval if it is more than would be visible on the screen double interval = TickFrequency; if (interval > 0.0) { double minInterval = range / size.Height; if (interval < minInterval) { interval = minInterval; } } Action <double, double> drawer = (tick, y) => { var formattedText = GetFormattedText(tick, textBrush, textTypeface, valueConverter, valueConverterParameter); var textPoint = new Point(startPoint.X - formattedText.Width / 2, y - (textPointShiftDirection * formattedText.Height)); double newTextEdge = y + (isDirectionReversed ? 1 : -1) * formattedText.Width / 2; bool drawThisText = true; if (eliminateOverlapping) { if (isDirectionReversed) { drawThisText = DoubleUtil.GreaterThanOrClose(y - formattedText.Width / 2, prevTextEdge) && DoubleUtil.LessThanOrClose(y + formattedText.Width / 2, maxTextEdge); } else { drawThisText = DoubleUtil.LessThanOrClose(y + formattedText.Width / 2, prevTextEdge) && DoubleUtil.GreaterThanOrClose(y - formattedText.Width / 2, maxTextEdge); } } if (drawThisText) { var rotateTransform = new RotateTransform(270, textPoint.X + formattedText.Width / 2, textPoint.Y + textPointShiftDirection * formattedText.Height); dc.DrawEllipse(textBrush, pen, new Point(startPoint.X, y), pointRadius, pointRadius); dc.PushTransform(rotateTransform); dc.DrawText(formattedText, textPoint); dc.Pop(); prevTextEdge = newTextEdge; } }; // Draw Min tick drawer(min, startPoint.Y); // Draw ticks using specified Ticks collection if ((ticks != null) && (ticks.Count > 0)) { foreach (double tick in ticks) { if (DoubleUtil.LessThanOrClose(tick, min) || DoubleUtil.GreaterThanOrClose(tick, max)) { continue; } double adjustedTick = tick - min; double y = adjustedTick * logicalToPhysical + startPoint.Y; drawer(tick, y); } } // Draw ticks using specified TickFrequency else if (interval > 0.0) { for (double i = interval; i < range; i += interval) { double y = i * logicalToPhysical + startPoint.Y; drawer(i + min, y); } } // Draw Max tick drawer(max, endPoint.Y); } else // Placement == Top || Placement == Bottom { double prevTextEdge = isDirectionReversed ? (controlActualWidth + startSpace) : (0.0 - startSpace); double maxTextEdge = isDirectionReversed ? (0.0 - endSpace) : (controlActualWidth + endSpace); // Reduce tick interval if it is more than would be visible on the screen double interval = TickFrequency; if (interval > 0.0) { double minInterval = range / size.Width; if (interval < minInterval) { interval = minInterval; } } Action <double, double> drawer = (tick, x) => { var formattedText = GetFormattedText(tick, textBrush, textTypeface, valueConverter, valueConverterParameter); var textPoint = new Point(x - (formattedText.Width / 2), startPoint.Y + textPointShiftDirection * formattedText.Height); double newTextEdge = textPoint.X + (isDirectionReversed ? 0.0 : formattedText.Width); bool drawThisText = true; if (eliminateOverlapping) { if (isDirectionReversed) { drawThisText = DoubleUtil.LessThanOrClose(textPoint.X + formattedText.Width, prevTextEdge) && DoubleUtil.GreaterThanOrClose(textPoint.X, maxTextEdge); } else { drawThisText = DoubleUtil.GreaterThanOrClose(textPoint.X, prevTextEdge) && DoubleUtil.LessThanOrClose(textPoint.X + formattedText.Width, maxTextEdge); } } if (drawThisText) { dc.DrawEllipse(textBrush, pen, new Point(x, startPoint.Y), pointRadius, pointRadius); dc.DrawText(formattedText, textPoint); prevTextEdge = newTextEdge; } }; // Draw Min tick drawer(min, startPoint.X); // Draw ticks using specified Ticks collection if ((ticks != null) && (ticks.Count > 0)) { foreach (double tick in ticks) { if (DoubleUtil.LessThanOrClose(tick, min) || DoubleUtil.GreaterThanOrClose(tick, max)) { continue; } double adjustedTick = tick - min; double x = adjustedTick * logicalToPhysical + startPoint.X; drawer(tick, x); } } // Draw ticks using specified TickFrequency else if (interval > 0.0) { for (double i = interval; i < range; i += interval) { double x = i * logicalToPhysical + startPoint.X; drawer(i + min, x); } } // Draw Max tick drawer(max, endPoint.X); } }