How Do I Assign Different Functions/ClickEvents To Buttons Inside A DatagridColumn In WPF?

Viewed 87

I have successfully created a DataGrid with WPF (C#) and bonded the buttons...However I now would like to bind a different event to each individual button instead. I plan to rename the buttons and open different file locations on my PC.

C#

wpfCrudEntities _db = new wpfCrudEntities();
public static DataGrid datagrid;

public MainWindow()
{
    InitializeComponent();
    Load();
}

private void Load()
{
    myDataGrid.ItemsSource = _db.members.ToList();
    datagrid = myDataGrid;
}

private void insertBtn_Click(object sender, RoutedEventArgs e)
{
    InsertPage Ipage = new InsertPage();
    Ipage.ShowDialog();
}
private void updateBtn_Click(object sender, RoutedEventArgs e)
{
    int Id = (myDataGrid.SelectedItem as member).id;
    UpdatePage Upage = new UpdatePage(Id);
    Upage.ShowDialog();
}
private void deleteBtn_Click(object sender, RoutedEventArgs e)
{
    int Id = (myDataGrid.SelectedItem as member).id;
    var deleteMemeber = _db.members.Where(m => m.id == Id).Single();
    _db.members.Remove(deleteMemeber);
    _db.SaveChanges();
    myDataGrid.ItemsSource = _db.members.ToList();
}

}

XAML

    <Window x:Class="wappppa.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:wappppa"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="600">
    <DockPanel>
        <DataGrid x:Name="myDataGrid" x:FieldModifier="public" AutoGenerateColumns="False" ColumnWidth="*" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Id" Binding="{Binding id}" />
                <DataGridTextColumn Header="Name" Binding="{Binding name}" />
                <DataGridTextColumn Header="Gender" Binding="{Binding gender}" />
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="Action" />
                    </DataTemplate>
                </DataGridTemplateColumn.HeaderTemplate>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Button x:Name="insertBtn" Content="Insert" Click="insertBtn_Click"/>
                            <Button x:Name="updateBtn" Content="Update" Click="updateBtn_Click"/>
                            <Button x:Name="deleteBtn" Content="Delete" Click="deleteBtn_Click"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
         </DataGrid.Columns>
        </DataGrid>
    </DockPanel>
</Window>
3 Answers

Using the MVVM pattern you define a ViewModel for your rows.
Then you can use a CommandBinding to bind the Button Click event to the ViewModel of the respective row.

In your case this would be the Member class that needs to be wrapped in a MemberViewModel where the 3 coammnds are defined.

I created a sample project to show you how you one way of use the DataGrid with the MVVM design.

I also added a Call ViewModel button just to show you how you can call commands in the ViewModel.

Caution Unfortunately, there's a bug and you need to add this to your project file. This bug will go away soon I guess.

Member.cs

using System;

namespace WpfAppDataGrid;

public class Member
{
    public Guid ID { get; set; } = Guid.NewGuid();
    public string Name { get; set; } = string.Empty;
    public string Gender { get; set; } = string.Empty;
}

MainViewModel.cs

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;

namespace WpfAppDataGrid;

// This class needs to be "partial"
// so the CommunityToolkit's source generator can create code for you.
public partial class MainWindowViewModel : ObservableObject
{
    // The source generator will auto-create a
    // "Member" property with INotifyPropertyChanged implemented.
    [ObservableProperty]
    private ObservableCollection<Member>? members = new()
    {
        new Member() { Name = "Ted", Gender="Male" },
        new Member() { Name = "Tracy", Gender="Female"},
        new Member() { Name = "Marshal", Gender = "Male" },
        new Member() { Name = "Lily", Gender = "Female" },
        new Member() { Name = "Robin", Gender = "Female" },
        new Member() { Name = "Barney", Gender = "Male" },
        new Member() { Name = "Ranjit", Gender = "Male" },
    };

    // The source generator will auto-create a "CallViewModelCommand" command.
    [RelayCommand]
    private void CallViewModel(Member member)
    {
    }
}

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace WpfAppDataGrid;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public MainWindowViewModel ViewModel { get; } = new();

    private void InsertButton_Click(object sender, RoutedEventArgs e)
    {
        if (sender is Button button && button.DataContext is Member member)
        {
            string name = member.Name;
        }
    }

    private void UpdateButton_Click(object sender, RoutedEventArgs e)
    {
    }

    private void DeleteButton_Click(object sender, RoutedEventArgs e)
    {
    }
}

MainWindow.xaml

<Window
    x:Class="WpfAppDataGrid.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfAppDataGrid"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="ThisWindow"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <StackPanel>
        <DataGrid
            x:Name="MyDataGrid"
            x:FieldModifier="public"
            AutoGenerateColumns="False"
            ColumnWidth="*"
            ItemsSource="{Binding ElementName=ThisWindow, Path=ViewModel.Members}">
            <DataGrid.Columns>
                <DataGridTextColumn
                    Binding="{Binding ID}"
                    Header="ID" />
                <DataGridTextColumn
                    Binding="{Binding Name}"
                    Header="Name" />
                <DataGridTextColumn
                    Binding="{Binding Gender}"
                    Header="Gender" />
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Text="Action" />
                        </DataTemplate>
                    </DataGridTemplateColumn.HeaderTemplate>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Button
                                    x:Name="InsertButton"
                                    Click="InsertButton_Click"
                                    Content="Insert" />
                                <Button
                                    x:Name="UpdateButton"
                                    Click="UpdateButton_Click"
                                    Content="Update" />
                                <Button
                                    x:Name="DeleteButton"
                                    Click="DeleteButton_Click"
                                    Content="Delete" />
                                <Button
                                    Command="{Binding ViewModel.CallViewModelCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
                                    CommandParameter="{Binding}"
                                    Content="ViewModel Command" />
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel>
</Window>

When a button click event fired you can access convert the sender object to a button and do whatever you want.

private void Button_Click(object sender, RoutedEventArgs e)
    {
        var clickedButton= (Button)sender;
        // Do whatever you want
    }
Related