简体   繁体   English

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

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

I'm building an app which will display a list of buttons in 2D grid, similar to How to populate a WPF grid based on a 2-dimensional array我正在构建一个将在二维网格中显示按钮列表的应用程序,类似于如何基于二维数组填充 WPF 网格

The challenge is to tell which button (in terms of i, j) was clicked in the buttonClick event handler.挑战在于判断在buttonClick事件处理程序中单击了哪个按钮(根据 i、j)。

My initial thought was to make the button name include a string representation of the i,j (eg 'button_2_3'), but it is not possible to specify the name using '{binding...}'.我最初的想法是使按钮名称包含 i,j 的字符串表示形式(例如“button_2_3”),但无法使用“{binding...}”指定名称。

It is NOT possible to use the button label ( button.content ), as the application requirement are to display non-unique labels on the buttons (the buttons label represent the piece on the cell, similar to chess, where the 'Q' label indicate the queens position).不能使用按钮标签 ( button.content ),因为应用程序要求在按钮上显示非唯一标签(按钮标签代表单元格上的棋子,类似于国际象棋,其中 'Q' 标签指示皇后的位置)。

The best alternative seems to store a representation of the row/column in the CommandParameter attribute of the button.最好的替代方法似乎是在按钮的 CommandParameter 属性中存储行/列的表示。

My Question: How to populate the CommandParameter of each button in such a way that it will be simple to extract the (i, j) of the clicked button?我的问题:如何填充每个按钮的 CommandParameter,以便轻松提取单击按钮的 (i, j)? Is there a better alternative to attach user defined data to a button?将用户定义的数据附加到按钮是否有更好的选择?

From: How to populate a WPF grid based on a 2-dimensional array来自: 如何基于二维数组填充 WPF 网格

<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>

And

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);
}

替代文字

You may bind the Button's Tag property您可以绑定 Button 的 Tag 属性

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

and use it in a Clicked handler like this:并在这样的 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);
}

It may also be simpler to use a single ItemsControl with a UniformGrid as ItemsPanel:使用带有 UniformGrid 作为 ItemsPanel 的单个 ItemsControl 也可能更简单:

<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>

and bind its ItemsSource to a List<int> :并将其 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;
}

You can use a type for a button viewmodel instead of the list of int.您可以为按钮视图模型使用类型而不是 int 列表。

Then bind 'name' inside of the content and button will contains your object in the DataContext.然后在内容中绑定“名称”,按钮将在 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>

Ps Instead of the button "сlick" event "command" property can be used. Ps 可以使用“сlick”事件“command”属性代替按钮。 Than command property should be added to the ButtonViewModel.应该将命令属性添加到 ButtonViewModel。 This is a proper MVVM way.这是一种正确的 MVVM 方式。 Also ButtonViewModel should implement IPropertyChanged interface to notify interface about the value changes.此外,ButtonViewModel 应该实现 IPropertyChanged 接口以通知接口有关值的更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM