Игра Tic Tac Toe с использованием WPF + MVVM

Мне нужен совет о том, как создать новую ViewModel в уже существующей ViewModel.

Я создаю игру Tic Tac Toe, чтобы улучшить свои знания о шаблоне MVVM, WPF и C #. Я хочу содержать кнопки (TileViewModel) как отдельные модели ViewModels и внедрить их в окно игры (GameViewModel). Я составил список TileViewModels в GameViewModel и добавил 9 из этих представлений в XAML, привязав список в ViewModel к каждому представлению, используя DataContext с индексом массива.

GameViewModel.cs

using MvvmCross.Commands;
using MvvmCross.ViewModels;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using TicTacToe.Core.Models;

namespace TicTacToe.Core.ViewModels
{
    public class GameViewModel : MvxViewModel, IBaseViewModel
    {
        private string nextValue = "X";
        private bool _won;
        public List<TileViewModel> ViewTiles { get; set; }

        public GameViewModel() {
            Grid grid = new Grid();
            grid.Start();

            ViewTiles = new List<TileViewModel> { 
                new TileViewModel(this),
                new TileViewModel(this),
                new TileViewModel(this),
                new TileViewModel(this),
                new TileViewModel(this),
                new TileViewModel(this),
                new TileViewModel(this),
                new TileViewModel(this),
                new TileViewModel(this)
            };
        }

        public string GetNextValue()
        {
            // Get the next value to display on the TileViewModel
            nextValue = nextValue.Equals("X") ? "O" : "X";

            return nextValue;
        }

        public bool Won
        {
            get { return _won; }
            set
            {

                _won = value;
            }
        }

        private void blockWon()
        {

        }

        public bool CheckForWin()
        {
            int AddValue(string tileValue)
            {
                if (tileValue.Equals("X"))
                {
                    return 1;
                }
                else if(tileValue.Equals("O"))
                {
                    return -1;
                }
                return 0;
            }

            // check rows
            int total = 0;
            for (int i=0; i<ViewTiles.Count; i++)
            {
                if (i % 3 == 0)
                {
                    if (Math.Abs(total) == 3)
                    {
                        Won = true;
                    }
                    total = 0;
                }

                total += AddValue(ViewTiles[i].Value);
            }

            // check columns
            total = 0;
            int loop_count = 0;
            for (int i=0; i<ViewTiles.Count; i++)
            {
                if (i % 3 == 0 && i != 0)
                {
                    if (Math.Abs(total) == 3)
                    {
                        Won = true;
                    }
                    loop_count++;
                    total = 0;
                }

                total += AddValue(ViewTiles[((i % 3) * 3) + loop_count].Value);
            }

            return false;
        }
    }
}

GameView.xaml

<views:MvxWpfView
             xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
             xmlns:customviews="clr-namespace:TicTacToe.Wpf.Views"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TicTacToe.Wpf.Views"
             xmlns:mvx="clr-namespace:MvvmCross.Platforms.Wpf.Binding;assembly=MvvmCross.Platforms.Wpf" xmlns:ViewModels="clr-namespace:TicTacToe.Core.ViewModels;assembly=TicTacToe.Core" x:Class="TicTacToe.Wpf.Views.GameView"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <customviews:TileView DataContext="{Binding ViewTiles[0]}" Grid.Column="0" Grid.Row="0"/>
        <customviews:TileView DataContext="{Binding ViewTiles[1]}" Grid.Column="1" Grid.Row="0"/>
        <customviews:TileView DataContext="{Binding ViewTiles[2]}" Grid.Column="2" Grid.Row="0"/>
        <customviews:TileView DataContext="{Binding ViewTiles[3]}" Grid.Column="0" Grid.Row="1"/>
        <customviews:TileView DataContext="{Binding ViewTiles[4]}" Grid.Column="1" Grid.Row="1"/>
        <customviews:TileView DataContext="{Binding ViewTiles[5]}" Grid.Column="2" Grid.Row="1"/>
        <customviews:TileView DataContext="{Binding ViewTiles[6]}" Grid.Column="0" Grid.Row="2"/>
        <customviews:TileView DataContext="{Binding ViewTiles[7]}" Grid.Column="1" Grid.Row="2"/>
        <customviews:TileView DataContext="{Binding ViewTiles[8]}" Grid.Column="2" Grid.Row="2"/>
    </Grid>
</views:MvxWpfView>

TielViewModel.cs

using MvvmCross.ViewModels;
using MvvmCross.Commands;
using System;
using System.Collections.Generic;
using System.Text;

namespace TicTacToe.Core.ViewModels
{
    public class TileViewModel : MvxViewModel
    {
        private string _value = "";
        private bool _enabled = true;
        private IBaseViewModel _baseViewModel;
        public IMvxCommand TileClick { get; set; }

        public TileViewModel(IBaseViewModel baseViewModel)
        {
            TileClick = new MvxCommand(Increment);

            _baseViewModel = baseViewModel;
        }

        public string Value {
            get { return _value;  } 
            set
            {
                _value = value;
                RaisePropertyChanged(() => Value);
            }
        }

        public bool Enabled
        {
            get { return _enabled; }
            set
            {
                _enabled = value;
                RaisePropertyChanged(() => Enabled);
            }
        }

        public void Increment()
        {
            Enabled = false;
            Value = _baseViewModel.GetNextValue();
            _baseViewModel.CheckForWin();
        }
    }
}

TileView.xaml

<views:MvxWpfView x:Class="TicTacToe.Wpf.Views.TileView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TicTacToe.Wpf.Views"
             mc:Ignorable="d"
             xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
             xmlns:mvx="clr-namespace:MvvmCross.Platforms.Wpf.Binding;assembly=MvvmCross.Platforms.Wpf"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Button mvx:Bi.nd="Command TileClick" IsEnabled="{Binding Enabled}">
            <TextBlock Text="{Binding Value}"/>
        </Button>
    </Grid>
</views:MvxWpfView>

Реализованное мной решение работает хорошо, мне просто было интересно, есть ли лучший способ реализовать подобное решение.

Я специально использую MVVMCross, но я думаю, что это скорее общее решение MVVM.

Спасибо!

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *