WPF - 游戏网格

本文关键字:网格 游戏网 游戏 WPF | 更新日期: 2023-09-27 18:15:39

我有WPF应用程序,一个数独游戏。我有一个游戏网格(9x9 正方形(的模型和用户控件。因为我的绑定知识有限,而且没有足够的时间,所以我决定让它变得老式,没有数据绑定和手动同步模型和视图。但是,它非常不干净,并且会出现同步问题。

我决定转换为正确的数据绑定。

我想我的网格应该是类似于项目控件(列表框或组合框(的东西,但它不是线性列表,而是将其项目布局为二维网格。

我是绑定新手,我不知道如何实现我的目标。我有模型类,其中包含有关当前拼图的一些一般信息,并包含单元格的集合。每个单元格都有自己的属性,如值、可能性、状态等。

我有用户对整个网格的控制,并拥有每个单独单元格的用户控制权。我需要网格绑定到模型的某些属性(例如,禁用,启用,数独类型(,并且每个单元格绑定到我相应的单元格 - 值,背景等。

编辑:单元格在可观察的集合中。每个单元格都有 X 和 Y 属性。我认为它们应该以某种方式绑定到 Grid.Row 和 Grid.Column 属性。

你能给我指出一些方向如何继续吗?特别是创建该项控件以及如何绑定到它?

谢谢。

WPF - 游戏网格

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);