我正在使用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>
答案 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
绑定附加到视图。
摘要:单独的逻辑和演示。处理数据。让控件根据绑定和提供的模板生成内容。
答案 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/