WPF - 游戏网格

时间:2011-11-25 17:42:53

标签: c# .net wpf data-binding

我有wpf应用程序,数独游戏。我有一个游戏网格的模型和用户控件(9x9平方)。因为我对绑定的了解有限而且我没有足够的时间,所以我决定在没有数据绑定的情况下使其成为旧的方式,并且手动同步模型和视图。然而,这是非常不洁净和同步问题出现。

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

我认为我的网格应该像itemscontrol(listbox或combobox),但不是线性列表,而是将其项目布局为二维网格。

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

我可以控制每个单元格的整个网格和用户控制。我需要网格绑定到我的模型的一些属性(例如,禁用,启用,数独类型)和每个单元格绑定到我相应的单元格 - 值,背景等。

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

你能指点一下如何继续吗?特别是创建itemscontrol以及如何绑定它?

谢谢。

2 个答案:

答案 0 :(得分:1)

1)是否可以观察到? - 不,你可以使用例如List<List<CellModel>>()
2)如果你仍想使用数组[,] - 如果你想使用ItemsControl
,你可能需要某种转换器 3)您可以使用ItemTemplate控制项目,也可以是项目控件
希望这会有所帮助

编辑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"/> - 这将使您的线条呈现为水平

编辑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>

答案 1 :(得分:0)

您不需要使用ObservableCollection绑定到集合,但是如果您希望自动实现CollectionChange通知,则建议使用它。

这意味着如果您更新集合(例如,清除它并开始新游戏),它将自动告知UI集合已更改,UI将使用新元素重绘自己。

您还可以使用ObservableCollections的Linq语句查找特定元素。例如,以下内容将返回与指定条件匹配的第一个单元格,如果未找到任何项目,则返回null

var cell = MyCollection.FirstOrDefault(
    cell => cell.Y == desiredRowIndex && cell.X == desiredColumnIndex);