制作NxN tic tac toe GUI wpf c#

我在WPF c#中制作一个NxN tic tac toe游戏。 我希望用户输入行数和列数(NxN),我的代码将生成这些列数和行数。 我无法弄清楚,我将如何动态生成该行数和列数。 我发布了我的XAML代码,有没有办法可以循环我的XAML代码? 谢谢

              

ItemsControl + UniformGrid作为面板是显示矩形游戏板的不错选择。 我已经发布了类似的解决方案( 如何创建和使用(颜色)框C#WPF的矩阵 )但它缺少行和列绑定。 这是TicTacToe的一个更详细的例子。

让我们创建视图模型类:

 public class BoardCell : INotifyPropertyChanged { private string _sign; private bool _canSelect = true; public string Sign { get { return _sign; } set { _sign = value; if (value != null) CanSelect = false; OnPropertyChanged(); } } public bool CanSelect { get { return _canSelect; } set { _canSelect = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } 
 public class Board { public int Rows { get; set; } public int Columns { get; set; } private ObservableCollection _cells; public ObservableCollection Cells { get { if (_cells == null) _cells = new ObservableCollection(Enumerable.Range(0, Rows*Columns).Select(i => new BoardCell())); return _cells; } } } 

然后创建一个视图:

                  

在代码隐藏中我们有一种方法允许2个玩家依次进行他们的移动:

 private bool _firstPlayer = true; private void CellClick(object sender, RoutedEventArgs e) { var cell = (sender as Button).DataContext as BoardCell; cell.Sign = _firstPlayer ? "X" : "O"; _firstPlayer = !_firstPlayer; // TODO check winner } 

遵循MVVM模式这个方法应该被包装成一个命令( ICommand ),移动到Board类并通过Button.Command绑定附加到视图。

一些转弯后的板子

摘要:单独的逻辑和演示。 处理数据。 让控件根据绑定和提供的模板生成内容。

我在我的博客上有一些AttachedProperties的代码就是这样做的。

XAML代码最终看起来像这样:

  

这是附加属性的代码,以防博客post链接出现故障。 它还包括一些用于指定Star行/列的属性。

 public class GridHelpers { #region RowCount Property ///  /// Adds the specified number of Rows to RowDefinitions. /// Default Height is Auto ///  public static readonly DependencyProperty RowCountProperty = DependencyProperty.RegisterAttached( "RowCount", typeof(int), typeof(GridHelpers), new PropertyMetadata(-1, RowCountChanged)); // Get public static int GetRowCount(DependencyObject obj) { return (int)obj.GetValue(RowCountProperty); } // Set public static void SetRowCount(DependencyObject obj, int value) { obj.SetValue(RowCountProperty, value); } // Change Event - Adds the Rows public static void RowCountChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e) { if (!(obj is Grid) || (int)e.NewValue < 0) return; Grid grid = (Grid)obj; grid.RowDefinitions.Clear(); for (int i = 0; i < (int)e.NewValue; i++) grid.RowDefinitions.Add( new RowDefinition() { Height = GridLength.Auto }); SetStarRows(grid); } #endregion #region ColumnCount Property ///  /// Adds the specified number of Columns to ColumnDefinitions. /// Default Width is Auto ///  public static readonly DependencyProperty ColumnCountProperty = DependencyProperty.RegisterAttached( "ColumnCount", typeof(int), typeof(GridHelpers), new PropertyMetadata(-1, ColumnCountChanged)); // Get public static int GetColumnCount(DependencyObject obj) { return (int)obj.GetValue(ColumnCountProperty); } // Set public static void SetColumnCount(DependencyObject obj, int value) { obj.SetValue(ColumnCountProperty, value); } // Change Event - Add the Columns public static void ColumnCountChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e) { if (!(obj is Grid) || (int)e.NewValue < 0) return; Grid grid = (Grid)obj; grid.ColumnDefinitions.Clear(); for (int i = 0; i < (int)e.NewValue; i++) grid.ColumnDefinitions.Add( new ColumnDefinition() { Width = GridLength.Auto }); SetStarColumns(grid); } #endregion #region StarRows Property ///  /// Makes the specified Row's Height equal to Star. /// Can set on multiple Rows ///  public static readonly DependencyProperty StarRowsProperty = DependencyProperty.RegisterAttached( "StarRows", typeof(string), typeof(GridHelpers), new PropertyMetadata(string.Empty, StarRowsChanged)); // Get public static string GetStarRows(DependencyObject obj) { return (string)obj.GetValue(StarRowsProperty); } // Set public static void SetStarRows(DependencyObject obj, string value) { obj.SetValue(StarRowsProperty, value); } // Change Event - Makes specified Row's Height equal to Star public static void StarRowsChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e) { if (!(obj is Grid) || string.IsNullOrEmpty(e.NewValue.ToString())) return; SetStarRows((Grid)obj); } #endregion #region StarColumns Property ///  /// Makes the specified Column's Width equal to Star. /// Can set on multiple Columns ///  public static readonly DependencyProperty StarColumnsProperty = DependencyProperty.RegisterAttached( "StarColumns", typeof(string), typeof(GridHelpers), new PropertyMetadata(string.Empty, StarColumnsChanged)); // Get public static string GetStarColumns(DependencyObject obj) { return (string)obj.GetValue(StarColumnsProperty); } // Set public static void SetStarColumns(DependencyObject obj, string value) { obj.SetValue(StarColumnsProperty, value); } // Change Event - Makes specified Column's Width equal to Star public static void StarColumnsChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e) { if (!(obj is Grid) || string.IsNullOrEmpty(e.NewValue.ToString())) return; SetStarColumns((Grid)obj); } #endregion private static void SetStarColumns(Grid grid) { string[] starColumns = GetStarColumns(grid).Split(','); for (int i = 0; i < grid.ColumnDefinitions.Count; i++) { if (starColumns.Contains(i.ToString())) grid.ColumnDefinitions[i].Width = new GridLength(1, GridUnitType.Star); } } private static void SetStarRows(Grid grid) { string[] starRows = GetStarRows(grid).Split(','); for (int i = 0; i < grid.RowDefinitions.Count; i++) { if (starRows.Contains(i.ToString())) grid.RowDefinitions[i].Height = new GridLength(1, GridUnitType.Star); } } } 

正如Zohar所提到的,您可以使用后面的代码将子GridColumn添加到Grid.ColumnDefinitions,然后将Button添加到Container Grid。 这是一个简单的方法,但它意味着使用后面的代码会导致许多皱眉。

就个人而言,我宁愿创建一个行为并将其附加到网格。 将您的行为绑定到viewmodel上的行和列的整数,然后将ColumnDefinitions和RowDefinitions添加到AssociatedObject。 行为是封装可重用function的好方法,并且无需编写代码。

本教程演示了如何创建绑定到模型的行为,以及如何将它们附加到视图中的元素。

http://julmar.com/blog/programming/playing-with-wpf-behaviors-a-watermarktext-behavior/