GeometryGroup

42

Простейший способ комбинировать геометрические фигуры — воспользоваться объектом GeometryGroup и поместить внутрь него другие объекты, унаследованные от Geometry. Ниже приведен пример размещения эллипса рядом с квадратом:

<Path Fill="Yellow" Stroke="Blue" Margin="5" Canvas.Top="10" Canvas.Left="10">
   <Path.Data>
      <GeometryGroup>
         <RectangleGeometry Rect = "0,0 100, 100"></RectangleGeometry>
         <EllipseGeometry Center="150,50" RadiusX="35" RadiusY="25"></EllipseGeometry>
      </GeometryGroup>
   </Path.Data>
</Path>

Эффект от этой разметки будет таким же, как от использования элементов Path — одного RectangleGeometry и одного EllipseGeometry (это то же самое, что и применение фигур Rectangle и Ellipse). Однако данный подход обладает одним преимуществом. Два элемента заменяются одним, что сокращает накладные расходы, связанные с пользовательским интерфейсом. В общем случае окно, в котором используется меньшее количество элементов с более сложной геометрией, работает быстрее, чем окно с огромным числом элементов более простой геометрии. Этот эффект не слишком заметен в окне с несколькими десятками фигур, но становится существенным, когда речь идет о сотнях или тысячах фигур.

Конечно, с комбинированием геометрий в один элемент Path связаны и отрицательные моменты, а именно: исчезает возможность индивидуальной обработки событий в разных фигурах. Вместо этого все события мыши инициируются элементом Path. Однако есть возможность манипулировать вложенными объектами RectangleGeometry и EllipseGeometry независимо, изменяя общий путь. Например, каждая геометрия предоставляет свойство Transform, которое можно применять для растягивания, деформации или поворота этой части пути.

Другое преимущество геометрий проявляется в том, что одну и ту же геометрию можно повторно использовать в нескольких разных элементах Path. Никакого кода не понадобится — геометрия просто определяется в коллекции Resources, а ссылка на нее в пути производится через расширения разметки StaticExtension или DynamicExtension.

Элемент GeometryGroup становится еще более интересным, когда фигуры пересекаются. Вместо простой трактовки рисунка как комбинации сплошных фигур, GeometryGroup использует свое свойство FillRule (которое может принимать значение EvenOdd или Nonzero) для принятия решений о том, какие фигуры закрашивать. Посмотрим, что произойдет, если после кода разметки, показанного ранее, поместить эллипс поверх квадратам:

<Path Fill="Yellow" Stroke="Blue" Margin="5" Canvas.Top="10" Canvas.Left="10">
   <Path.Data>
      <GeometryGroup>
         <RectangleGeometry Rect="0,0 100,100"></RectangleGeometry>
         <EllipseGeometry Center="50,50" RadiusX="35" RadiusY="25"></
                    EllipseGeometry>
      </GeometryGroup>
   </Path.Data>
</Path>

Теперь этот код разметки создает квадрат с отверстием в нем в форме эллипса. Если изменить FillRule на Nonzero, то получится сплошной эллипс поверх сплошного квадрата — оба они закрашены желтым.

Путь, использующий две фигуры
Пройди тесты
Лучший чат для C# программистов