Для большинства целей помещение их в ControlTemplate или DataTemplate работает лучше всего. Вот способ ControlTemplate:
<ResourceDictionary>
<ControlTemplate x:Key="MyShape">
<Grid With="..." Height="...">
<Rectangle ... />
<Ellipse ... />
<Path ... />
</Grid>
</ControlTemplate>
</ResourceDictionary>
...
<Canvas ...>
<Control Template="{StaticResource MyShape}" ... />
<Control Template="{StaticResource MyShape}" ... />
<Control Template="{StaticResource MyShape}" ... />
<Control Template="{StaticResource MyShape}" ... />
</Canvas>
И способ DataTemplate:
<ResourceDictionary>
<DataTemplate x:Key="MyShape">
<Grid With="..." Height="...">
<Rectangle ... />
<Ellipse ... />
<Path ... />
</Grid>
</DataTemplate>
</ResourceDictionary>
...
<Canvas ...>
<ContentPresenter ContentTemplate="{StaticResource MyShape}" ... />
<ContentPresenter ContentTemplate="{StaticResource MyShape}" ... />
<ContentPresenter ContentTemplate="{StaticResource MyShape}" ... />
<ContentPresenter ContentTemplate="{StaticResource MyShape}" ... />
</Canvas>
Чтобы выбрать между ними, решите, какие дополнительные функции (если они есть) вам нужны. Возможно, вы захотите добавить свойства в свой элемент управления или объект данных.
- Если вы используете ControlTemplate, ваш пользовательский элемент управления может участвовать в наследовании свойств и быть частью визуального дерева, получая все события. Вы также можете ссылаться как на DataContext, так и на TemplatedParent в привязках, что более гибко.
- Если вы используете DataTemplate, вы можете работать непосредственно с объектами в вашей модели.
Вместо перечисления отдельных элементов управления вы также можете использовать ItemsControl и его подклассы (ListBox, ComboBox и т. Д.) Для правильного представления ваших фигур.
Альтернативный подход
Еще один совершенно другой подход - преобразовать вашу коллекцию фигур в объект Drawing и представить ее с помощью DrawingImage или DrawingBrush.