Мне нужно написать элемент управления датчиком в WPF для проекта на работе. Под манометром я подразумеваю что-то вроде традиционного автомобильного спидометра: круглая циферблат с цифрами и делениями по окружности и стрелка, указывающая на текущее значение. Хотя я мог бы заставить своего работодателя купить сторонний элемент управления или даже найти где-нибудь бесплатный, я все же хотел бы написать его сам, больше всего ради любопытства.
Моя первая мысль заключалась в том, чтобы «скрыть» существующий элемент управления с помощью шаблона, например, что-то вроде ProgressBar, поскольку он имеет свойства Minimum, Maximum и Value. Однако я не думаю, что это даст мне необходимую гибкость.
Я хотел бы анимировать стрелку, указывающую на текущее значение, чтобы при изменении значения датчика стрелка перемещалась от старого значения к новому значению. Я полагал, что самый простой способ сделать это — иметь какую-то форму или геометрию, представляющую стрелку, а затем применить RotateTransform с соответствующим числом градусов, чтобы стрелка указывала на правильное значение. Свойство To анимации будет установлено на свойство «степени значения» через привязку.
Мне кажется, что есть три основных подхода, которые я мог бы использовать:
Используйте один пользовательский FrameworkElement для представления всего датчика
Я мог бы получить от FrameworkElement, переопределить его метод OnRender, а затем использовать DrawingContext для рисования лицевой стороны датчика и стрелки. Это означало бы, что я больше не мог бы анимировать стрелку напрямую с помощью RotateTransform, а вместо этого должен был бы перерисовывать всю шкалу каждый раз, когда значение изменяется. Мне это кажется неэффективным, так как поверхность датчика представляет собой большую часть кода рисования, но меняется очень редко. Однако этот подход является самым легковесным с точки зрения количества используемых элементов.
Используйте два пользовательских элемента FrameworkElements, один для лица и один для иглы
Сейчас я склоняюсь к этому подходу. Один элемент будет представлять лицо, другой — иглу. Это позволило бы мне нацелить элемент иглы с помощью RotateTransform. В этом случае элемент управления датчиком будет состоять из трех элементов: лица, иглы и контейнера Panel для их хранения (т. е. Canvas, Grid и т. д.). Таким образом, три элемента вместо одного, следовательно, не такие легкие, как первый подход.
Используйте DrawingVisuals для рисования лица и иглы
Я также читал о классе DrawingVisual, но я немного сбит с толку тем, почему кто-то может использовать его, а не производный от FrameworkElement и переопределение OnRender, учитывая, что DrawingVisual в любом случае должен размещаться в пользовательском FrameworkElement. Казалось бы, этот подход не дает никаких преимуществ перед вторым подходом и потребует больше кода, но, возможно, я что-то упускаю.
Любые мысли или советы относительно того, какой подход люди считают лучшим и почему, будут приветствоваться!