制作NxN tic tac toe GUI wpf c#

时间:2017-03-29 15:27:56

标签: c# wpf xaml

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

<Grid x:Name="Container">
    <!-- First here i want to make N columns-->
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <!-- Here i want to make N rows-->
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!-- Then here i want to add that number of buttons in N x N columns and rows -->
    <Button x:Name="Button0_0" Grid.Row="0" Grid.Column="0" Click="Button_Click"/>
    <Button x:Name="Button0_1" Grid.Row="0" Grid.Column="1" Click="Button_Click" />
    <Button x:Name="Button0_2" Grid.Row="0" Grid.Column="2" Click="Button_Click"/>

    <Button x:Name="Button1_0" Grid.Row="1" Grid.Column="0" Click="Button_Click"/>
    <Button x:Name="Button1_1" Grid.Row="1" Grid.Column="1" Click="Button_Click"/>
    <Button x:Name="Button1_2" Grid.Row="1" Grid.Column="2" Click="Button_Click"/>

    <Button x:Name="Button2_0" Grid.Row="2" Grid.Column="0" Click="Button_Click"/>
    <Button x:Name="Button2_1" Grid.Row="2" Grid.Column="1" Click="Button_Click"/>
    <Button x:Name="Button2_2" Grid.Row="2" Grid.Column="2" Click="Button_Click"/>                                                  
</Grid>

3 个答案:

答案 0 :(得分:1)

ItemsControl + UniformGrid作为面板是显示矩形游戏板的不错选择。我已经发布了类似的解决方案(How to create and use matrix of (color) boxes C# WPF),但它缺少Rows和Columns绑定。以下是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<BoardCell> _cells;
    public ObservableCollection<BoardCell> Cells
    {
        get
        {
            if (_cells == null)
                _cells = new ObservableCollection<BoardCell>(Enumerable.Range(0, Rows*Columns).Select(i => new BoardCell()));
            return _cells;
        }
    } 
}

然后创建一个视图:

<Grid x:Name="Container">
    <Grid.DataContext>
        <wpfDemos:Board Rows="8" Columns="8"/>
    </Grid.DataContext>
    <ItemsControl x:Name="Board" ItemsSource="{Binding Path=Cells}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate >
                <UniformGrid Rows="{Binding Path=Rows}" Columns="{Binding Path=Columns}"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Content="{Binding Path=Sign}" 
                        IsEnabled="{Binding Path=CanSelect}"
                        Click="CellClick"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>
在代码隐藏中,我们有一种方法允许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绑定附加到视图。

board after some turns

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

答案 1 :(得分:0)

我有code for some AttachedProperties on my blog就是这样做的。

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

<Grid local:GridHelpers.RowCount="{Binding RowCount}"
      local:GridHelpers.ColumnCount="{Binding ColumnCount}" />

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

public class GridHelpers
{
    #region RowCount Property

    /// <summary>
    /// Adds the specified number of Rows to RowDefinitions. 
    /// Default Height is Auto
    /// </summary>
    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

    /// <summary>
    /// Adds the specified number of Columns to ColumnDefinitions. 
    /// Default Width is Auto
    /// </summary>
    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

    /// <summary>
    /// Makes the specified Row's Height equal to Star. 
    /// Can set on multiple Rows
    /// </summary>
    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

    /// <summary>
    /// Makes the specified Column's Width equal to Star. 
    /// Can set on multiple Columns
    /// </summary>
    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);
        }
    }
}

答案 2 :(得分:0)

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

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

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

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