Страницы

Поиск по вопросам

четверг, 4 октября 2018 г.

Экспоненциальная запись в TextBlock

Как в DataGridTextColumn реализовать переход на экспоненциальную запись, когда не хватает места для полного отображения числа.
Желаемый эффект:

Есть идея использовать конвертор, и вызывать его всякий раз при изменении ширины колонки. В конверторе использовать StringFormat. Возникают дополнительные вопросы:
на какое событие нужно подписаться которое бы отслеживало изменение размера колонки? как определять сколько символов влезает в ячейку, чтобы знать сколько символов отобразить после запятой и до E?
P.S. Что-то подобное делает свойство TextTrimming="CharacterEllipsis" у TextBlock. при нехватке места для отображения часть символов заменяется многоточием. Если узнать каким способом TextBlock определяет что ему не хватает места отобразить текст, то может и получиться решить данный вопрос.


Ответ

По идее, для этого можно приспособить UserControl и немного code-behind. Для измерения ширины текста без отображения подойдёт класс FormattedText. Вот простой набросок:
Контрол:

Code-behind:
public partial class DoubleWidthFitControl : UserControl { public DoubleWidthFitControl() { InitializeComponent(); SizeChanged += (o, args) => Recalc(); }
#region dp double Value public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } }
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof(double), typeof(DoubleWidthFitControl), new PropertyMetadata(0.0, (o, args) => ((DoubleWidthFitControl)o).Recalc())); #endregion
void Recalc() { var targetWidth = ActualWidth; var num = Value;
string s; // у C# 7 есть локальные функции, вау! bool CheckLength(string format) { s = num.ToString(format); return Measure(s) <= targetWidth; }
if (CheckLength("F") || CheckLength("G")) { Target.Text = s; return; }
int i; for (i = 0; CheckLength($"E{i}"); i++) /**/; if (i == 0) Target.Text = "###"; else Target.Text = num.ToString($"E{i - 1}"); }
double Measure(string s) { TextBlock tb = Target; var formattedText = new FormattedText( s, CultureInfo.CurrentCulture, tb.FlowDirection, new Typeface(tb.FontFamily, tb.FontStyle, tb.FontWeight, tb.FontStretch), tb.FontSize, Brushes.Black); return formattedText.Width; } }
Использовать просто:

Результат:

Есть хороший потенциал для дальнейшей оптимизации. Например, при данной строке и шрифте можно один раз подсчитать и запомнить варианты отображения с их размерами, и просто подбирать наибольший вписывающийся.

Комментариев нет:

Отправить комментарий