Какой смысл в украшениях WPF?
Недавно я разработал компонент для рисования для своей компании, включающий Canvas, на котором вы можете рисовать определенные фигуры, используя щелчок и перетаскивание. Для каждой фигуры я поместил два украшателя на ее слой AdornerLayer: один для увеличения обнаружения попаданий (в основном прозрачный прямоугольник, который на несколько пикселей превысил бы границы фигуры), а другой для изменения размера (четыре элемента управления Thumb по углам).
Но я столкнулся с множеством проблем при реализации некоторых функций компонента, связанных с рекламой.
Они захватили все события предварительного просмотра, так как они были в другом визуальном дереве, чем сам Canvas, что было неожиданным, но я нашел обходной путь, даже если он мне не очень понравился. Использование AdornerDecorator не решило эту проблему, а выбранный мной рекламный элемент - черная дыра для событий предварительного просмотра.
Когда я реализовал манипуляцию z-index с фигурами на Canvas (отправка назад, перенос вперед и т. Д.), Все работало нормально с использованием Panel.SetZIndex, как и следовало ожидать. Но украшатели в другом визуальном дереве! таким образом, они не были затронуты, и украшения выбора были ВСЕ ЕЩЕ поверх всех других форм, даже если эти формы были поверх той, для которой украшение выбора обнаруживало попадания. Например: Shape1, SelectionAdorner1. Shape2, SelectionAdorner2. Shape1 находится сверху (добавлен позже на холст) Shape2, поэтому перекрывает его. Таким образом, щелчок по нему будет обнаружен SelectionAdorner1. Я манипулировал ZIndex, чтобы отправить его обратно, теперь Shape2 находится сверху и перекрывает Shape1. Я нажимаю на верхней части Shape2, но щелчок обнаруживается SelectionAdorner1 вместо SelectionAdorner2. Это было особенно раздражающим. Так что, очевидно, поскольку Adorners находятся на другом визуальном дереве, они не уважают ZIndexes. Я попытался решить эту проблему, создав DataBinding (а также вручную) между ZIndex фигуры и ZIndex его SelectionAdorner. Но это не решило проблему. Изменение ZIndex of Adorners не повлияло на то, как они отображались на экране, может быть, я что-то упустил, но это не должно быть так сложно, так как Adorners должны быть сделаны, чтобы сделать вещи проще. Единственное решение, которое я мог придумать, - это вручную удалить все украшения и добавить их вручную, один за другим, добавив, наконец, тот, который должен был быть сверху. Это было отсталым, но это сработало.
Далее, Adorners не уважают ClipToBounds! Я установил ClipToBounds=true на холсте, на котором я рисовал, и он работал нормально, но чертовы украшения все равно будут работать! Решение этой проблемы было относительно безболезненным, я просто добавил AdornerDecorator поверх каждой фигуры. Не идеальное решение IMO, но достаточно простое.
Украсители не всегда хорошо реагируют на преобразования LayoutTransforms, выполняемые на их украшенных элементах. У меня есть панель поверх холста, которая реализует функции Zoom и Pan. Он использовал анимацию, чтобы сделать масштабирование более плавным. Но использование анимации привело к тому, что мои Adorners стали обезьянами! При первом увеличении они просто игнорируют изменение размера и сохраняют тот же размер и положение, а при втором увеличении они масштабируются до предыдущего размера украшенного элемента. Это не имеет никакого смысла! Единственное решение, которое я смог найти, - отключить анимацию, которая, к счастью, сработала.
Я не совсем помню, какие у меня были другие проблемы, но этого было более чем достаточно, чтобы заставить меня задуматься о полезности Adorners, и я серьезно думаю о том, чтобы не использовать их в моем следующем проекте, который похож на тот, который я описал,
Итак, кто-нибудь может сказать мне, что может быть плюсом в использовании этих, казалось бы, полезных, но невероятно раздражающих вещей?
Благодарю.
1 ответ
Я думаю, что вы уже знаете ответ на свой вопрос. Они экономят время в одних аспектах и вызывают проблемы в других. Если бы вы должны были кодировать это поведение дизайнера, используя множество UserControls, вы бы написали множество шаблонных управляющих классов, чтобы обернуть элементы, которые вы на самом деле хотели редактировать. Если, с другой стороны, вы пытались написать отдельные элементы управления для редактирования и интеллектуально наложить их, вы бы писали стандартный код, чтобы синхронизировать их позиции и размеры. Подход, который вы выбрали, с использованием украшателей, привел к созданию большого (довольно стандартного) кода для управления событиями.
Хотя украшения могут быть не лучшим инструментом для выполнения этой конкретной задачи, они все же являются полезным инструментом для других, более простых задач. Недавно я написал подобный вид "дизайнерской поверхности", и украшения были удачной находкой для двух частей:
- Поведение перетаскивания. Когда я перетаскивал разные элементы, они должны были иметь разные визуальные превью; это было удивительно легко сделать с помощью специального рекламодателя и шаблонов данных.
- Прямоугольник выделения или "лассо". Нечто подобное можно увидеть, когда вы удерживаете левую кнопку мыши на рабочем столе Windows и перетаскиваете указатель мыши. Он создает полупрозрачный блок, в котором можно выбрать несколько элементов. Я смог создать это поведение практически мгновенно со слоем adorner, тогда как создание собственного пользовательского элемента управления привело к большому количеству ненужного бухгалтерского учета.
Я думаю, что вы обнаружили в своем проекте, что вы, возможно, использовали украшения, чтобы попытаться сделать слишком много. Но не выбрасывайте ребенка с водой - они все еще очень полезны в определенных ситуациях.