WPF Units и Code-Behind - PullRequest
       40

WPF Units и Code-Behind

14 голосов
/ 29 февраля 2012

Недавно я обнаружил, что WPF поддерживает различные единицы измерения в XAML. Помимо DIP по умолчанию, есть также поддержка пикселей, дюймов и сантиметров (насколько я знаю). Это позволяет разработчику написать XAML, например:

<Canvas>
    <Line X1="0cm" X2="3cm" Y1="1cm" Y2="3cm" Stroke="Black"/>
</Canvas>

Однако вы не можете связать эти значения. Представьте, что у нас есть свойство ViewModel with Dimension, которое представляет собой строку, например «7cm». Следующее не будет работать:

<Button Width="{Binding Dimension}">Test</Button>

Выдается исключение FormatException. Точно так же при создании FrameworkElement в коде позади, как это:

Canvas1.Children.Add(new Button() { Width = "3cm", Content = "Test"});

Компиляция завершается неудачно, потому что исключение выдается в конструкторе / везде, где вы пытаетесь создать элемент управления.

Интересно:

  • Можно ли использовать натуральные единицы (в моем случае метрические - сантиметры) в коде позади?
  • Как?
  • Существует ли полный список устройств, поддерживаемых WPF / XAML?

EDIT:

Вот ссылка из комментария ниже, которая решает этот вопрос:

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.width.aspx

Ответы [ 2 ]

14 голосов
/ 01 марта 2012

Вы можете сделать это в коде позади, применив то же преобразование, которое использует XAML-парсер, вам не нужно переопределять эту логику, если вы не против передачи строк:

button.Width = (double)new LengthConverter().ConvertFrom("2cm");

XAML-parser использует TypeConverters для преобразования строк в нужные значения. На странице документации свойства Width вы можете видеть, что он имеет TypeConverterAttributeуказав, что следует использовать LengthConverter.Этот атрибут можно использовать для локального переопределения способа обработки свойства, но его также можно применять на уровне класса, поэтому, если у класса Employee есть этот атрибут, указывающий, что следует использовать EmployeeConverter, указанный конвертер будет использоваться по умолчанию.для свойств типа Employee.

Я немного удивлен, что привязка не применяет этот преобразователь типов, но использовать его внутри IValueConverter было бы достаточно просто, фактически вы могли бы создать расширение разметки , которое создает IValueConverter из преобразователя типов, чтобы сделать его достаточно общим.

2 голосов
/ 29 февраля 2012

Для 1) и 2) Поскольку DIP не зависят от устройства, вы можете без проблем вычислить любую «натуральную единицу». Исключением являются (неестественно :) зависящие от устройства пиксели.

Создайте ValueConverter , который преобразует строковые значения в двойные, где в строке могут быть указаны желаемые единицы. Затем вы можете использовать ValueConverter в своем Binding и вычислять в ViewModel в «натуральных единицах».

Для 3) и реализации: я быстро нагуглил и ничего не нашел, но, может быть, более глубокий поиск покажет что-нибудь. В противном случае создание собственного конвертера не должно быть очень сложным. Вот некоторые сведения о преобразовании:

96DIP == 1inch == 2.54cm;
1cm == 37.8DIP;
1zoll == 1inch == 2.54cm;
...