пятница, 16 сентября 2011 г.

Связывание данных - выводим числа

Продолжаю тему про конвертеры в WPF.

В программе для анализа проектных данных, над которой я работаю в последнее время, требуется выводить много числовых данных, сопровождаемых существительными. Например 5 дней, 48 часов, 10 проектов, 4 сотрудника. Обратите внимание, что падеж существительного изменяется в зависимости от числа которое перед ним. Так, фраза “Осталось 41 дней” выглядит некрасиво и, естественно, немного раздражает. Вставлять отдельную логику вывода в каждом из многочисленных текстовых полей, в которых требуется выводить подобные данные, мне не хотелось, а хотелось сделать некоторое обобщенное решение задачи вывода в пользовательском интерфейсе числовых данных с существительными в правильном падеже.

В результате я сделал очень простой класс-конвертер данных, который решает описанную задачу. В свойствах конвертера при его создании указываются строки, соответствующие нужным падежам, когда говорят 1 день, 2(3,4) дня или 5(6,7,8,9) дней. Эти свойства так и называются String1, String234, String56789. Отдельным свойством задается значение для 0. Строка может включать в себя как просто существительное (как указано выше), так и строку форматирования, например: остался {0} день, осталось {0} дней.

Конвертеры для всех требуемых существительных декларируются в словаре ресурсов, например так:

<FormatNumberStringConverter x:Key="SheduledWorksCountConverter"
String1="Запланирована {0} работа"
String234="Запланированы {0} работы"
String56789="Запланировано {0} работ"
/>



Для использования конвертера нужно объявить его в свойствах привязки к данными:


<TextBlock Text="{Binding IncompletedWorks.Target.Count, Converter={StaticResource SheduledWorksCountConverter}}" />


в итоге получается вот так:


image


Да! чуть не забыл Подмигивающая рожица - сам конвертер для числовых данных:


public class FormatNumberStringConverter : UniConverter
{
public string Zero {get;set;}
/// <summary>
/// единственное число именительныйй падеж
/// </summary>
public String String1 {get; set;}

/// <summary>
/// единственное число родительный падеж
/// </summary>
public String String234 {get;set;}

/// <summary>
/// множественное число родительный падеж
/// </summary>
public String String56789 { get; set; }

/// <summary>
/// формирует текстовое представление для выражений вида 1 день, 5 недель и т.п.
/// т.е. число + существительное в правильном падеже и числе
/// </summary>
/// <param name="Number">Целое число</param>
public string GetString(int Number)
{
if (Number == 0 && !String.IsNullOrEmpty(Zero))
return Zero;

int x = Number % 100;

string s = String56789;
if (x < 10 || x > 20)
{
x = x % 10;
if (x == 1)
s = String1;
else if (x > 1 && x < 5)
s = String234;
}

if (s.Contains("%%"))
s = s.Replace("%%", "{0}");

if (s.Contains("{0}"))
return string.Format(CultureInfo.CurrentCulture, s, Number);

return string.Format(CultureInfo.CurrentCulture, "{0} {1}", Number, s);
}

public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return base.Convert(value, targetType, parameter ?? "GetString", culture);
}
}


Буду рад, если кому-нибудь пригодится.


Полезное свойство такого конвертера – все строки помещаются в XAML и могут быть использованы для локализации приложения.

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

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