1

Имеется TextBlock с фрагментами текста, имеющими разные размеры шрифта, заданные в параметре <Run>:

<TextBlock><Run FontSize="14pt">15,</Run><Run FontSize="10pt">555333</Run></TextBlock>

Как будет грамотно обновлять эти значения из кода?

Если указать свойство Text, то применится значение для всего текста и шрифт будет везде одинаковый:

MyTextBlock.Text = "15,555333";

Пробовал делать так, но при постоянном увеличении числа с последующим обновлением текста он создается заново и его приходится очищать:

// этот код находится в цикле
MyTextBlock.Text = null;
MyTextBlock.Inlines.Add(new Run("15,") { FontSize = 16 });
MyTextBlock.Inlines.Add(new Run("555333") { FontSize = 12 });

Как будет правильнее обновлять данные в TextBlock?

denisnumb
  • 5,710
  • 2
    Привязки научитесь делать. У вас не должно быть создания контролов в коде вообще. – EvgeniyZ Sep 11 '21 at 16:27

1 Answers1

2

Не знаю, насколько это правильно, в смысле вот таким образом разбивать число, но мне метод показался самым очевидным - использовать конвертер.

Например у вас есть класс, реализующий INotifyPropertyChanged, на него вы настроили DataContext и в нем свойство, например такое.

private double _number;

public double Number { get => _number; set { _number = value; OnPropertyChanged(); } }

Как реализовать INotifyPropertyChanged и настроить DataContext, я не буду рассказывать, но я раньше уже публиковал это, например здесь и здесь, можно на StackOverflow найти и множество других примеров.

Теперь можно создать вот такой класс-конвертер.

public enum DoublePart
{
    Integer, Fraction
}

public class DoubleSplitConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is double number && parameter is string optionText && Enum.TryParse(optionText, out DoublePart option) && Enum.IsDefined(option)) { string text = number.ToString(culture); int index = text.IndexOf(culture.NumberFormat.NumberDecimalSeparator); switch (option) { case DoublePart.Integer: return index >= 0 ? text.Remove(index) : text; case DoublePart.Fraction: return index >= 0 ? text.Substring(index) : string.Empty; } } return null; }

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    throw new NotSupportedException(&quot;Преобразование double в обратную сторону не поддерживается&quot;);
    // здесь ничего нет, но при желании можно сделать обратную конвертацию, хотя я не представляю, зачем
}

}

Код предельно прост, я думаю вы без труда сможете его прочитать

Конвертер подключить к окну просто

<Window.Resources>
    <local:DoubleSplitConverter x:Key="DoubleSplitConverter"/>
</Window.Resources>

Тогда привязка данных текстблока будет выглядеть вот так

<TextBlock>
    <Run FontSize="14pt" Text="{Binding Number, Converter={StaticResource DoubleSplitConverter}, ConverterParameter=Integer, ConverterCulture=RU_ru}"/><Run FontSize="10pt" Text="{Binding Number, Converter={StaticResource DoubleSplitConverter}, ConverterParameter=Fraction, ConverterCulture=RU_ru}"/>
</TextBlock>

Обратите внимание, что Run расположены в одну строку - это на самом деле важно. Если сделать перенос строки в XAML, между ними будет пробел в окне.

Кстати, если убрать ConverterCulture=RU_ru, будет использоваться культура по умолчанию - EN_us, то есть дробь будет с точкой. Культуру интерфейса по умолчанию тоже можно изменить.

Вот и всё, теперь вы можете присваивать в коде

Number = Math.PI;

И число будет корректно отображаться в интерфейсе. Подредактировав код конвертера можно применить необходимое форматирование.


Второй не менее очевидный способ реализации - сделать UserControl и инкапсулировать всю логику в нём, без конвертера.

aepot
  • 49,560
  • 1
    Мне кажется, не обязательно приводить parameter к enum, wpf умеет делать это самостоятельно. Хотя, здесь параметр object же, да, тогда не получится. Сработало бы, если бы мы использовали для этого отдельное свойство в конвертере, а не параметр конвертирующей функции – Андрей NOP Sep 12 '21 at 09:21
  • 1
    А по поводу культуры есть этот ответ: https://ru.stackoverflow.com/a/950972/218063 – Андрей NOP Sep 12 '21 at 09:23
  • @АндрейNOP спасибо, про культуру дополнил ответ. Про enum уже тоже погрустил, пока код писал. – aepot Sep 12 '21 at 09:34
  • 1
    Ага, я, чтоб не грустить, использую такой подход: https://ru.stackoverflow.com/a/981982/218063 – Андрей NOP Sep 12 '21 at 09:41