WPF - игровая сетка - PullRequest
       3

WPF - игровая сетка

0 голосов
/ 25 ноября 2011

У меня есть приложение wpf, игра в судоку. У меня есть модель и пользовательский элемент управления для игровой сетки (9x9 квадратов). Поскольку мои знания о связывании ограничены и у меня не было достаточно времени, я решил сделать это по-старому без привязки к данным и ручной синхронизации модели и представления. Однако это очень нечисто, и возникают проблемы с синхронизацией.

Я решил преобразовать в правильную привязку данных.

Полагаю, моя сетка должна быть чем-то вроде itemscontrol (listbox или combobox), но вместо линейного списка она будет размещать свои элементы в двумерной сетке.

Я новичок в связывании и понятия не имею, как достичь своей цели. У меня есть класс модели, который имеет некоторую общую информацию о текущей головоломке и содержит коллекцию клеток. Каждая ячейка имеет свои собственные свойства, такие как значение, возможности, состояние и т. Д.

У меня есть пользовательский контроль всей сетки и пользовательский контроль для каждой отдельной ячейки. Мне нужна сетка для привязки к некоторым свойствам моей модели (например, отключена, включена, типа судоку) и каждая ячейка для привязки к моей соответствующей ячейке - значение, фон и т. Д.

РЕДАКТИРОВАТЬ: ячейка находится в наблюдаемой коллекции. Каждая ячейка имеет свойство X и Y. Я думаю, что они должны как-то связываться со свойствами Grid.Row и Grid.Column.

Не могли бы вы указать мне направление, как продолжить? Особенно создание этого элемента управления и как его связать?

Спасибо.

Ответы [ 2 ]

1 голос
/ 25 ноября 2011

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>
0 голосов
/ 25 ноября 2011

Вам не нужно использовать ObservableCollection для привязки к коллекции, однако рекомендуется, если вы хотите, чтобы уведомление CollectionChange было реализовано автоматически.

Это означает, что если вы обновите свою коллекцию (например, очистите ее и запустите новую игру), она автоматически сообщит пользовательскому интерфейсу, что коллекция изменилась, и пользовательский интерфейс будет перерисовывать себя с новыми элементами.

Вы также можете использовать операторы Linq с помощью ObservableCollections, чтобы найти определенный элемент.Например, следующее вернет первую ячейку, которая соответствует заданным критериям, или ноль, если элемент не найден

var cell = MyCollection.FirstOrDefault(
    cell => cell.Y == desiredRowIndex && cell.X == desiredColumnIndex);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...