Вам все равно придется использовать выделенный код для изменения свойств RowDefinitions
и ColumnDefinitions
Grid
в этом примере, поскольку они не являются свойствами зависимости. Но вся остальная логика может быть обработана в классе модели представления.
XAML:
<Window x:Class="GameBoard.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:GameBoard="clr-namespace:GameBoard"
Title="Window1"
SizeToContent="WidthAndHeight">
<Grid Margin="50">
<Grid.Resources>
<!-- This template presents the Piece object. Note that you can't set
the Grid.Row and Grid.Column properties on this Rectangle - well,
you *can*, but the Grid won't see them. See the Style below. -->
<DataTemplate DataType="{x:Type GameBoard:Piece}">
<Rectangle Fill="{Binding Fill}"
Width="50"
Height="50" />
</DataTemplate>
<!-- When the ItemsControl creates its items, it wraps each item in a
ContentPresenter. You have to set Grid.Row and Grid.Column
on this ContentPresenter in order for the Grid to see them. -->
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Grid.Row"
Value="{Binding Row}" />
<Setter Property="Grid.Column"
Value="{Binding Column}" />
</Style>
</Grid.Resources>
<Border BorderBrush="Black"
BorderThickness="1">
<ItemsControl x:Name="Board"
ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Border>
</Grid>
</Window>
Класс Piece
- очевидно, вам потребуется реализовать INotifyPropertyChanged
в свойствах Row
и Column
для обработки движущихся частей вокруг.
public class Piece
{
public int Column { get; set; }
public Brush Fill { get; set; }
public int Row { get; set; }
}
Заполнение доски:
public Window1()
{
InitializeComponent();
ObservableCollection<Piece> pieces = new ObservableCollection<Piece>();
pieces.Add(
new Piece {Row = 0, Column = 0, Fill = new SolidColorBrush(Colors.BlanchedAlmond)});
pieces.Add(
new Piece {Row = 7, Column = 7, Fill = new SolidColorBrush(Colors.RosyBrown)});
pieces.Add(
new Piece { Row = 3, Column = 4, Fill = new SolidColorBrush(Colors.BlueViolet) });
pieces.Add(
new Piece { Row = 5, Column = 4, Fill = new SolidColorBrush(Colors.Orange) });
Board.DataContext = pieces;
}
Я использовал ItemsControl
, чтобы содержать кусочки в этом примере. Вместо этого вы могли бы использовать ListBox
- это хорошо, потому что он дает вам выбор предметов бесплатно. Обратите внимание, что если вы сделаете это, вам придется изменить Style
TargetType
на ListBoxItem
, поскольку именно в него ListBox
оборачивает свои элементы item вместо ContentPresenter
.
Edit:
Я написал этот ответ довольно давно, и у него есть проблема.
Назначение свойств Grid.Row
и Grid.Column
с использованием стиля, применяемого к контейнеру элементов, сгенерированному сеткой, является правильным. Выяснить, что контейнер элемента является ContentPresenter
, а создать стиль по умолчанию для этого типа - нет. (В этом случае он будет работать надежно, но во многих случаях это не работает.)
Вы все равно должны создать стиль, но он должен быть назначен на ItemsControl
ItemContainerStyle
. Этот стиль автоматически применяется к любому элементу контейнера, который элемент управления генерирует для своих элементов - поэтому, если ItemsControl
вы используете ListBox
, он применяет его к ListBoxItem
, а если TabControl
, то он Применится к TabItem
и т. д.