Мне нужен совет о том, как создать новую 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.
Спасибо!