根据二维数组识别 WPF 网格中点击了哪个按钮

Identify which button was clicked in WPF gird based on 2D array

我正在构建一个应用程序,它将在二维网格中显示按钮列表,类似于 How to populate a WPF grid based on a 2-dimensional array

挑战在于判断在 buttonClick 事件处理程序中单击了哪个按钮(根据 i、j)。

我最初的想法是让按钮名称包含 i,j 的字符串表示形式(例如 'button_2_3'),但无法使用“{binding ...}”指定名称.

不能使用按钮标签 (button.content),因为应用程序要求在按钮上显示非唯一标签(按钮标签代表单元格上的棋子,类似于国际象棋,其中 'Q' 标签表示皇后位置)。

最好的替代方法似乎是在按钮的 CommandParameter 属性中存储 row/column 的表示。

我的问题:如何填充每个按钮的 CommandParameter 以便于提取单击按钮的 (i, j)?是否有更好的替代方法将用户定义的数据附加到按钮?

发件人:How to populate a WPF grid based on a 2-dimensional array

<Window.Resources>
<DataTemplate x:Key="DataTemplate_Level2">
        <Button Content="{Binding}" Height="40" Width="50" Margin="4,4,4,4" click="buttonClick"/>
</DataTemplate>

<DataTemplate x:Key="DataTemplate_Level1">
    <ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</DataTemplate>

public Window1()
{
    List<List<int>> lsts = new List<List<int>>();

    for (int i = 0; i < 5; i++)
    {
        lsts.Add(new List<int>());

        for (int j = 0; j < 5; j++)
        {
            lsts[i].Add(i * 10 + j);
        }
    }

    InitializeComponent();

    lst.ItemsSource = lsts;
}

private void buttonClick(object sender, EventArgs e)
{
  //do something or...
  Button clicked = (Button) sender;
  MessageBox.Show("Button's name is: " + clicked.Name);
}

您可以绑定按钮的标签属性

<Button Tag="{Binding}" .../>

并像这样在 Clicked 处理程序中使用它:

private void Button_Click(object sender, RoutedEventArgs e)
{
    int value = (int)((Button)sender).Tag;
    int row = value / 10;
    int column = value % 10;

    Debug.WriteLine("Clicked row {0}, column {1}", row, column);
}

使用带有 UniformGrid 的单个 ItemsControl 作为 ItemsPanel 可能会更简单:

<ItemsControl ItemsSource="{Binding}"
              HorizontalAlignment="Left" VerticalAlignment="Top">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Columns="5"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding}" Tag="{Binding}"
                    Height="40" Width="50" Margin="4" Click="Button_Click"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

并将其 ItemsSource 绑定到 List<int>:

public MainWindow()
{
    InitializeComponent();

    var list = new List<int>();

    for (int i = 0; i < 5; i++)
    {
        list.AddRange(Enumerable.Range(i * 10, 5));
    }

    DataContext = list;
}

您可以为按钮视图模型使用类型而不是 int 列表。

然后在内容和按钮内部绑定 'name' 将在 DataContext 中包含您的对象。

class ButtonViewModel
{
  public string Name {get;set;} 
  public int Value {get;set;} 
}  

public Window1()
{
    List<List<ButtonViewModel>> lsts = new List<List<ButtonViewModel>>();

    for (int i = 0; i < 5; i++)
    {
        lsts.Add(new List<ButtonViewModel>());

        for (int j = 0; j < 5; j++)
        {
            var model = new ButtonViewModel();
            model.Value = i * 10 + j;
            model.Name = "Q: "+ model.Value;
            lsts[i].Add(model);
        }
    }

    InitializeComponent();

    lst.ItemsSource = lsts;
}

private void buttonClick(object sender, EventArgs e)
{
  //do something or...
  Button clicked = (Button) sender;
  MessageBox.Show("Button's name is: " + (clicked.DataContext as ButtonViewModel).Name);
}

WPF:

<Window.Resources>
<DataTemplate x:Key="DataTemplate_Level2">
        <Button Content="{Binding Name}" DataContext={Binding} Height="40" Width="50" Margin="4,4,4,4" click="buttonClick"/>
</DataTemplate>

P.s。可以使用 "command" 属性 代替按钮“сlick”事件。应该将命令 属性 添加到 ButtonViewModel。这是一种正确的 MVVM 方式。此外,ButtonViewModel 应该实现 IPropertyChanged 接口以通知接口有关值的更改。