Определите, какая кнопка была нажата в WPF Gird на основе 2D-массива - PullRequest
0 голосов
/ 21 января 2020

Я создаю приложение, которое будет отображать список кнопок в двумерной сетке, аналогично Как заполнить сетку WPF на основе двумерного массива

Задача состоит в том, чтобы чтобы сказать, какая кнопка (в терминах i, j) была нажата в обработчике buttonClick.

Сначала я хотел, чтобы имя кнопки включало строковое представление i, j (например, 'button_2_3) '), но невозможно указать имя с помощью' {binding ...} '.

NOT возможно использовать метку кнопки (button.content), так как требование к приложению состоит в том, чтобы на кнопках отображались неуникальные метки (метка кнопок представляет фигуру в ячейке, аналогично шахматам, где метка «Q» указывает положение ферзей).

Кажется, лучшая альтернатива сохранить представление строки / столбца в атрибуте CommandParameter кнопки.

Мой вопрос: Как заполнить CommandParameter каждой кнопки таким образом, чтобы было просто извлечь (i, j) нажатой кнопки? Есть ли лучшая альтернатива для прикрепления пользовательских данных к кнопке?

От: Как заполнить сетку 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>

А

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

alt text

Ответы [ 2 ]

2 голосов
/ 21 января 2020

Вы можете связать свойство Tag кнопки

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

Также может быть проще использовать один ItemsControl с UniformGrid в виде 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;
}
1 голос
/ 21 января 2020

Вы можете использовать тип для кнопки viewmodel вместо списка 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>

Ps Вместо кнопки «щелкнуть» событие можно использовать свойство «команда». Свойство команды должно быть добавлено в ButtonViewModel. Это правильный путь MVVM. Также ButtonViewModel должен реализовывать интерфейс IPropertyChanged для уведомления интерфейса об изменениях значения.

...