Я хочу нарисовать прямоугольники с точно такими же свойствами, кроме одного, например, поля или цвета
Для меня это звучит как стиль. В WPF, как правило, есть несколько разных способов выполнить одно и то же, и это не исключение.
кажется, что установка модели представления немного завышена
Может быть. Возможно, нет. Трудно сказать, так как в вашем вопросе нет никаких других деталей. Тем не менее, учитывая приведенную выше формулировку проблемы, я бы согласился, что она, безусловно, не необходима , и при отсутствии каких-либо других требований я не вижу ничего, что можно было бы получить с помощью моделей представления.
Тем не менее, вот пример кода, который показывает три различных способа, два из которых основаны на моделях и шаблонах представления:
<Window x:Class="TestSO58683029RectStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="clr-namespace:TestSO58683029RectStyle"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<l:MainViewModel>
<l:MainViewModel.Rectangle1>
<l:RectangleViewModel Margin="2"/>
</l:MainViewModel.Rectangle1>
<l:MainViewModel.Rectangle2>
<l:RectangleViewModel Margin="5"/>
</l:MainViewModel.Rectangle2>
</l:MainViewModel>
</Window.DataContext>
<Window.Resources>
<p:Style TargetType="Rectangle">
<Setter Property="Width" Value="20"/>
<Setter Property="Height" Value="8"/>
<Setter Property="Fill" Value="Red"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</p:Style>
<DataTemplate DataType="{x:Type l:RectangleViewModel}">
<Rectangle Width="20" Height="8" Fill="Red" HorizontalAlignment="Left" Margin="{Binding Margin}"/>
</DataTemplate>
<x:Array x:Key="rectangleArray1" Type="{x:Type l:RectangleViewModel}">
<l:RectangleViewModel Margin="2"/>
<l:RectangleViewModel Margin="5"/>
</x:Array>
</Window.Resources>
<StackPanel>
<!-- Uses style -->
<Rectangle/>
<Rectangle Margin="2"/>
<Rectangle Margin="5"/>
<!-- Uses view models, individual properties -->
<ContentControl Content="{Binding Rectangle1}"/>
<ContentControl Content="{Binding Rectangle2}"/>
<!-- Uses view models, collection -->
<ItemsControl ItemsSource="{StaticResource rectangleArray1}"/>
</StackPanel>
</Window>
Подходы модели представления основаны на этих классах (они не реализуют INotifyPropertyChanged
потому что в этом простом примере нет необходимости):
class RectangleViewModel
{
public Thickness Margin { get; set; }
}
class MainViewModel
{
public RectangleViewModel Rectangle1 { get; set; }
public RectangleViewModel Rectangle2 { get; set; }
}
Как видно, в случае подхода, основанного на стилях, один элемент <Style/>
в словаре ресурсов может использоваться для определениязначения по умолчанию для любых свойств, которые вам нравятся. Затем вы можете явно использовать элемент <Rectangle/>
там, где вы хотите, в содержимом вашего окна, явно устанавливая любое другое свойство. Вы можете даже переопределить свойства, которые были установлены в стиле, если это необходимо по какой-либо причине.
Обратите внимание, что в приведенном выше примере шаблон данных явно устанавливает значения своих свойств. Но на самом деле вы можете объединить эти два метода, обращаясь к ресурсу стиля при объявлении шаблона, например, так:
<DataTemplate DataType="{x:Type l:RectangleViewModel}">
<Rectangle Margin="{Binding Margin}" Style="{StaticResource ResourceKey={x:Type Rectangle}}"/>
</DataTemplate>
Как отмечено в комментариях, объявление конкретных элементов пользовательского интерфейса в качестве ресурсов обычно является неправильный способ сделать что-то в WPF. Я не решаюсь сказать, что это всегда неправильно, но я бы сказал, что почти всегда неправильно. Конкретные элементы пользовательского интерфейса должны быть объявлены как фактическое содержимое в XAML со стилями, используемыми для обеспечения форматирования по умолчанию для этих элементов. В противном случае вам следует использовать шаблоны и разрешить WPF создавать элементы пользовательского интерфейса по мере необходимости на основе предоставленного вами шаблона.