Объяснение странного поведения отсечения
Теперь, когда вы опубликовали свой полный исходный код, я наконец смог увидеть то, что вы видели.Ваша проблема вовсе не в преобразовании: она в клипе!
- Если вы закомментируете оператор присваивания
container.Clip
, вы получите идентичные результаты независимо от того, включили ли вы преобразование container
или drawing
- Если вы раскомментировали оператор присваивания
container.Clip
, область отсечения идеально центрируется при преобразовании чертежа, но при преобразовании контейнера область отсечения смещается, так что только областьнижняя и правая линии прямоугольника были видны (и не все)
Причина, по которой это происходит, заключается в том, что геометрия, указанная для container.Clip
, является частью контейнера, поэтому на нее влияют container.Transform
но не drawing.Transform
:
Это можно лучше понять, посмотрев на верхние левые углы контейнера, рисунок, прямоугольник и область обрезки относительно верхнего левого угла окна:
Когда вы устанавливаете преобразование на чертеже:
- Контейнер в (0,0) относительно окна (нулевое преобразование)
- Область клипа в (20,20) относительно окна (нулевое преобразование + RectangleGeometry)
- Рисование в (20,20) относительно окна (нулевое преобразование + TranslateTransform)
- Прямоугольник в (20,20) относительно окна (нулевое преобразование + TranslateTransform + 0,0)
Когда вы устанавливаете преобразование для контейнера:
- Контейнер находится в (20,20) относительно окна (TranslateTransform)
- Область клипа находится в (40,40) относительно окна (TranslateTransform + RectangleGeometry)
- Рисование в (20,20) относительно окна (TranslateTransform + нулевое преобразование)
- Прямоугольник в (20,20) относительно окна (TranslateTransform + нулевое преобразование +0,0)
Так что ваша проблема не в том, что преобразование не происходит: оно заключается в том, что преобразование тоже перемещает область клипа, поэтому область клипа больше не совпадает с прямоугольником иВы можете видеть только две стороны прямоугольника.
Ответ дан для оригинального кода (сохранен, потому что он имеет некоторое полезное объяснение)
На самом деле, отправленный вами код никогда не использует «контейнер», поэтому все, что вы увидите, это пустой экран.
В вашем фактическом коде вы используете «контейнер» неправильно, не позволяя событиям происходить в правильной последовательности, что приводит к тому, что их Transform выбирается и передается в слой MIL.
Помните, что когда Visual имеетНабор преобразований, это не сам визуал, а тот визуальный родительский элемент , который фактически обрабатывает это преобразование.Например, если вы визуализируете страницу в XPS с помощью ReachFramework или выполняете тестирование попаданий, преобразование на внешнем визуальном объекте игнорируется.
Ваше понимание верно: если ваше визуальное дерево построено в соответствии со всеми правилами, оно неНеважно, находится ли ваше преобразование в вашем "контейнере" или в вашем "чертеже".
Поскольку вы все равно используете Control, мне любопытно, почему вы не просто позволяете обычной системе макетов на основе UIElement обрабатыватьВаш макет нуждается.
Первое обновление (сохраняется по той же причине)
Спасибо за исправление кода.Как я и подозревал, вы неправильно строите свое визуальное дерево.Если вы используете AddVisualChild, вы также должны переопределить GetVisualChild и VisuaChildrenCount.Это потому, что Visual не хранит список дочерних элементов: это зависит от подкласса (вашего класса).Происходит следующее:
- Когда вы вызываете AddVisualChild, преобразование контейнера становится нулевым, поэтому оно передается в MILCore.
- Позже, когда вы изменяете преобразование контейнера, он использует родительский указатель (который был установлен в AddVisualChild), чтобы сигнализировать, что его данные преобразования должны быть обновлены. Это обновление требует сканирования части визуального дерева с использованием GetVisualChild и VisualChildrenCount.
- Так как вы не реализовали эти методы, эта часть обновления завершается ошибкой.
Вы говорите, что вы "новичок в WPF". Знаете ли вы, что вы играете с некоторыми из самых низкоуровневых и эзотерических функций WPF, которые никогда не будут использоваться в самых обычных приложениях WPF? Это равносильно тому, чтобы начать изучать программирование с использованием машинного языка. Обычно для этой цели вы используете шаблоны с Path, Rectangle и т. Д. Иногда вы можете перейти на более низкий уровень и использовать DrawingBrush с DrawingGroup, содержащей GeometryDrawings и т. Д. Но вы почти никогда не пройдете весь путь до DrawingVisual и RenderOpen! Единственный раз, когда вы это сделаете, это когда у вас есть огромные чертежи, состоящие из миллионов отдельных элементов, и вы хотите обойти все накладные расходы на макеты и структуру верхних слоев для достижения абсолютной максимальной производительности.
Управление визуальным деревом самостоятельно (AddVisualChild и т. Д.) Также является расширенной функцией. Я всегда рекомендую новичкам в WPF придерживаться UIElement и выше в течение первых нескольких месяцев, используя Control с шаблонами. Я рекомендую использовать для своих чертежей Path и другие подклассы фигур, а также использовать VisualBrushes, когда требуются дополнительные эффекты рисования.
Надеюсь, это поможет.