如何在WPF中从网格内的标签中获取行和列信息?

如何在WPF中从网格内的标签中获取行和列信息?,wpf,grid,label,Wpf,Grid,Label,我有一个3x3的网格,我用它作为tic-tac-toe的游戏板。每个网格都有一个标签,可以显示“X”、“O”或“”。每个标签都包含其所在位置的行和列信息。我正试图从代码文件中获取这些信息。到目前为止,我已经: <Label Grid.Row="0" Grid.Column="0" Name="lblZeroxZero" MouseDown="lblZeroxZero_MouseDown" FontSize="72" Padding="5" HorizontalContent

我有一个3x3的网格,我用它作为tic-tac-toe的游戏板。每个网格都有一个标签,可以显示“X”、“O”或“”。每个标签都包含其所在位置的行和列信息。我正试图从代码文件中获取这些信息。到目前为止,我已经:

        <Label Grid.Row="0" Grid.Column="0" Name="lblZeroxZero" MouseDown="lblZeroxZero_MouseDown" FontSize="72" Padding="5" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
    <Label Grid.Row="0" Grid.Column="1" Name="lblZeroxOne" MouseDown="lblZeroxOne_MouseDown" FontSize="72" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
    <Label Grid.Row="0" Grid.Column="2" Name="lblZeroxTwo" MouseDown="lblZeroxTwo_MouseDown" VerticalContentAlignment="Center" FontSize="72" HorizontalContentAlignment="Center" />
    <Label Grid.Row="1" Grid.Column="0" Name="lblOnexZero" MouseDown="lblOnexZero_MouseDown" HorizontalContentAlignment="Center" FontSize="72" VerticalContentAlignment="Center" />
    <Label Grid.Row="1" Grid.Column="1" Name="lblOnexOne" MouseDown="lblOnexOne_MouseDown" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="72" />
    <Label Grid.Row="1" Grid.Column="2" Name="lblOnexTwo" MouseDown="lblOnexTwo_MouseDown" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="72" />
    <Label Grid.Row="2" Grid.Column="0" Name="lblTwoxZero" MouseDown="lblTwoxZero_MouseDown" FontSize="72" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" />
    <Label Grid.Row="2" Grid.Column="1" Name="lblTwoxOne" MouseDown="lblTwoxOne_MouseDown" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="72" />
    <Label Grid.Row="2" Grid.Column="2" Name="lblTwoxTwo" MouseDown="lblTwoxTwo_MouseDown" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="72">

目前,我知道如何获取标签的行和列信息的唯一方法是查看其名称。我希望获得Grid.Row和Grid.Column信息,而不必为每个标签名称创建一组特定的案例。

使用
GetRow
GetColumn
的附加属性
Grid
。范例

int row = Grid.GetRow(lblZeroxZero);
int column = Grid.GetColumn(lblZeroxZero);
更新

在你的情况下,你可以这样做

private int[] GetLabelPosition(Label lbl)
{
    return new int[] { Grid.GetRow(lbl), Grid.GetColumn(lbl) };
}

使用
GetRow
GetColumn
Grid
上附加的属性。范例

int row = Grid.GetRow(lblZeroxZero);
int column = Grid.GetColumn(lblZeroxZero);
更新

在你的情况下,你可以这样做

private int[] GetLabelPosition(Label lbl)
{
    return new int[] { Grid.GetRow(lbl), Grid.GetColumn(lbl) };
}

+1作为Meleak的第一个答案,但我还想建议,与其使用codebehind,不如使用数据绑定?这将大大简化您的代码。

+1是Meleak的第一个答案,但我还想建议您不要使用codebehind,为什么不使用数据绑定呢?它将大大简化您的代码。

正如OJ所建议的,您应该使用数据绑定。这使您可以将在屏幕上显示游戏的问题与管理游戏内部逻辑的问题分开

您需要创建一个
单元格
类,该类公开
所有者
属性。该类将需要实现
INotifyPropertyChanged
,以便当
所有者
发生更改时,它可以通过引发
PropertyChanged
事件来警告UI。最后,该类将实现一个
SelectCellCommand
,该命令将在执行单元格时适当地设置单元格的
所有者
(一旦设置了单元格的所有者,其
CanExecute
属性将设置为false)

您将创建一个集合,其中包含九个
单元格
,并将
、和
所有者
属性设置为适当的初始值。所有游戏逻辑(例如,轮到谁了?有人赢了吗?)都将检查此集合

在UI中,您将创建一个绑定到
单元格
集合的
ItemsControl
。控件中的每个项都将是网格中的一个单元格

您将
ItemsPanel
设置为
Grid
,这将告诉
ItemsControl
如何布置项目。您将创建一个
itemsContainerStyle
,它将
网格.Row
网格.Column
附加属性分配给项目的容器-
ItemsControl
ItemsSource
中的每个对象创建一个
itemsresenter
,必须在此对象上设置
Grid.Row
Grid.Column
属性,以便
Grid
能够看到它们并知道将它们放在何处

最后,该控件将包含一个
ItemTemplate
,该模板描述每个项目的显示方式。我使用的是一个
按钮(因为您希望有一个在用户单击时执行的命令),它包含一个
文本块
,在
所有者
中显示X或O

它可能看起来像这样:

<ItemsControl ItemsSource="{Binding {StaticResource Cells}}">
   <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
         <Grid>
            <Grid.ColumnDefinitions>
               <ColumnDefinition/>
               <ColumnDefinition/>
               <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
               <RowDefinition/>
               <RowDefinition/>
               <RowDefinition/>
            </Grid.RowDefinitions>
         </Grid>
      </ItemsPanelTemplate>
      <ItemsPanel.ItemContainerStyle>
         <Style TargetType="ItemPresenter">
            <Setter Property="Grid.Column" Value="{Binding Column}"/>
            <Setter Property="Grid.Row" Value="{Binding Row}"/>
         </Style>
      </ItemsPanel.ItemContainerStyle>
      <ItemsPanel.ItemTemplate>
         <DataTemplate DataType="local:Cell">
            <Button Command="{Binding SelectCellCommand}" VerticalContentAlignment="Center" HorizontalContentAlignment="Center">
               <TextBlock FontSize="72" Source="{Binding Owner}"/>
            </Button>                   
         </DataTemplate>
      </ItemsPanel.ItemTemplate>
   </ItemsControl>
</ItemsControl>

为什么要经历这一切

好吧,让我们来看看您当前的设计中存在的问题,这些问题没有:

  • 如果要更改设计中单元的布局,则需要修复九个不同的控件。在这里,您只需更改单元格的
    DataTemplate

  • 不需要九个不同的事件处理程序。由于按钮绑定到属于
    单元格属性的命令对象,因此不需要实现任何方法来查找用户刚刚单击的单元格-命令就是方法。此外,一旦设置了
    所有者
    ,您就可以非常简单地禁用该命令(及其按钮)

  • 您的所有游戏逻辑都可以查看一个简单的数据结构,即
    单元格
    对象的集合,而不必关心UI的工作方式


  • 最后,也是最重要的一点,数据绑定是WPF应用程序开发的核心。这使得开发WPF应用程序比实现WinForms应用程序容易得多。如果您在学习WPF时没有学习绑定,那么您就是在浪费时间。

    正如OJ所建议的,您应该使用数据绑定。这使您可以将在屏幕上显示游戏的问题与管理游戏内部逻辑的问题分开

    您需要创建一个
    单元格
    类,该类公开
    所有者
    属性。该类将需要实现
    INotifyPropertyChanged
    ,以便当
    所有者
    发生更改时,它可以通过引发
    PropertyChanged
    事件来警告UI。最后,该类将实现一个
    SelectCellCommand
    ,该命令将在执行单元格时适当地设置单元格的
    所有者
    (一旦设置了单元格的所有者,其
    CanExecute
    属性将设置为false)

    您将创建一个集合,其中包含九个
    单元格
    ,并将
    、和
    所有者
    属性设置为适当的初始值。所有游戏逻辑(例如。