WPF - 游戏网格
本文关键字:网格 游戏网 游戏 WPF | 更新日期: 2023-09-27 18:15:39
我有WPF应用程序,一个数独游戏。我有一个游戏网格(9x9 正方形(的模型和用户控件。因为我的绑定知识有限,而且没有足够的时间,所以我决定让它变得老式,没有数据绑定和手动同步模型和视图。但是,它非常不干净,并且会出现同步问题。
我决定转换为正确的数据绑定。
我想我的网格应该是类似于项目控件(列表框或组合框(的东西,但它不是线性列表,而是将其项目布局为二维网格。
我是绑定新手,我不知道如何实现我的目标。我有模型类,其中包含有关当前拼图的一些一般信息,并包含单元格的集合。每个单元格都有自己的属性,如值、可能性、状态等。
我有用户对整个网格的控制,并拥有每个单独单元格的用户控制权。我需要网格绑定到模型的某些属性(例如,禁用,启用,数独类型(,并且每个单元格绑定到我相应的单元格 - 值,背景等。
编辑:单元格在可观察的集合中。每个单元格都有 X 和 Y 属性。我认为它们应该以某种方式绑定到 Grid.Row 和 Grid.Column 属性。
你能给我指出一些方向如何继续吗?特别是创建该项控件以及如何绑定到它?
谢谢。
1(它应该是可观察的吗? - 不,您可以使用例如List<List<CellModel>>()
2(如果你想仍然使用array[,] - 如果你想使用ItemsControl
,你可能需要某种转换器3(您可以将项目控件与项目模板一起使用,这也
将是一个项目控件
希望这会有所帮助
编辑 1:让我们从第 2 点创建一个转换器...
public class ArrayConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var val = value as CellModel[,];
if (val == null) return null;
return ToEnumerable(val);
}
private IEnumerable<IEnumerable<CellModel>> ToEnumerable(CellModel[,] array)
{
var count = array.GetLength(0);
for (int i = 0; i < array.GetLength(0); ++i)
{
yield return GetLine(array, i);
}
}
private IEnumerable<CellModel> GetLine(CellModel[,] array, int line)
{
var count = array.GetLength(1);
for (int i = 0; i < count; ++i)
{
yield return array[line, i];
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
编辑 2:您的 xaml 可能如下所示(请参阅第 3 点(:
<Grid>
<Grid.Resources>
<Converters:ArrayConverter x:Key="ArrayConverter"/>
</Grid.Resources>
<ItemsControl
ItemsSource="{Binding CellArray, Mode=OneWay, Converter={StaticResource ArrayConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl
ItemsSource="{Binding ., Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- TODO: Add cell template here -->
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
编辑3:添加行<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
- 这将使您的行被渲染为horisontal
编辑 4:您的视图模型现在可以是这样的:
public class GameViewModel : ViewModelBase
{
public void Load()
{
var array = new CellModel[9, 9];
for (int i = 0; i < 9; ++i)
{
for (int j = 0; j < 9; ++j)
{
array[i, j] = new CellModel()
{
//TODO: init properties of the cell[i, j]
};
}
}
this.CellArray = array;
}
CellModel[,] _CellArray;
public CellModel[,] CellArray
{
get
{
return _CellArray;
}
private set
{
if (_CellArray == value) return;
_CellArray = value;
NotifyPropertyChanged("CellArray");
}
}
}
如果仍然不清楚,请告诉我
编辑5:根据上次编辑,让我们更改我们的 XAML:
<ItemsControl
ItemsSource="{Binding CellArray, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid
Grid.Column="{Binding X}"
Grid.Row="{Binding Y}">
<!-- TODO: -->
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid IsItemsHost="True">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
使用 ObservableCollection
绑定到集合,但是,如果要自动实现 CollectionChange 通知,建议使用。
这意味着,如果您更新集合(例如,清除集合并启动新游戏(,它将自动告诉 UI 集合已更改,并且 UI 将使用新元素重新绘制自身。
您还可以使用 ObservableCollections
的 Linq 语句来查找特定元素。例如,以下内容将返回与指定条件匹配的第一个单元格,如果未找到项目,则返回 null
var cell = MyCollection.FirstOrDefault(
cell => cell.Y == desiredRowIndex && cell.X == desiredColumnIndex);