Search code examples
c#.netwpfdatagridcaliburn.micro

Add a buttons to rows of DataGrid and Event_Click to each using Caliburn micro in WPF


I am trying to add a button "View" to to a series of rows (last cell of the row) of factures in DataGrid (using c#, WPF, Caliburn micro mvvm). Each button should have a handler that views the details of that facture in another form.

Questions:

  1. How can I add this button at row ends?
  2. How can I add the event handler?

I will only view the function that I am using to add the word "View" at the last column of each row.

I tried adding a button using: Button btn = new Button(); And set its required parameters. But that didn't work.

I will share the whole xaml and ViewModel files:

<UserControl x:Class="Factures.Views.FactureView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Factures.Views"
             xmlns:cal="http://www.caliburnproject.org"
             cal:Bind.Model="Shell"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800" FontFamily="Times New Roman">
    <Grid IsEnabled="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20" />
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="20" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20" />
            <RowDefinition Height="*" />
            <RowDefinition Height="20" />
        </Grid.RowDefinitions>
        <DataGrid AlternatingRowBackground="Gray" 
                  Grid.Column="1" Grid.Row="1"
                  x:Name="Factures"
                  ItemsSource="{Binding Factures}"
                  CanUserAddRows="False" 
                  MinWidth="100" MinHeight="50" 
                  FontFamily="Times New Roman"
                  AutoGenerateColumns="False" 
                  IsReadOnly="True"
                  >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Id" Binding="{Binding Path=Id}" />
                <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" />
                <DataGridTemplateColumn Header="View">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="BtnView"
                                    cal:Message.Attach="[Event Click]=[BtnView($dataContext)]"
                                    Content="View Facture">

                            </Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</UserControl>
using Caliburn.Micro;
using Factures.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Factures.ViewModels
{
    public class FactureViewModel : Conductor<object>
    {
        public BindableCollection<FactureModel> Factures { get; set; }

        public FactureViewModel()
        {
            FactureModel facture = new FactureModel();
            DataTable allFactures = facture.All();

            //Fill Bindable collection
            this.FillAllFactures(allFactures);
        }

        public void BtnView(object row)
        {
            MessageBox.Show("Hello");
        }   

        private void FillAllFactures(DataTable factures)
        {
            List<FactureModel> output = new List<FactureModel>();
            foreach(DataRow row in factures.Rows)
            {
                FactureModel fm = new FactureModel
                {
                    Id = System.Convert.ToInt32(row[0].ToString()),
                    Name = row[1].ToString(),
                };

                output.Add(fm);
            }
            this.Factures = new BindableCollection<FactureModel>(output);
        }
    }
}

Solution

  • You can use DataGridTemplateColumn and Caliburn Micro's Action message syntax to use a Button for each row in your datagrid.

    For first part of your question, you can add a button to each row of your Datagrid using DataGridTemplateColumn.

     <DataGridTemplateColumn>
         <DataGridTemplateColumn.CellTemplate>
             <DataTemplate>
                <Button Content="View" cal:Message.Attach="[Event Click]=[ViewUser($dataContext)]"></Button>
              </DataTemplate>
         </DataGridTemplateColumn.CellTemplate>
      </DataGridTemplateColumn>
    

    Complete definition of DataGrid in your XAML would look like.

    <DataGrid ItemsSource="{Binding Users}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Id}" Header="Id"/>
                <DataGridTextColumn Binding="{Binding UserName}" Header="UserName"/>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="View" cal:Message.Attach="[Event Click]=[ViewUser($dataContext)]"></Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    

    The cal:Message.Attach="[Event Click]=[ViewUser($dataContext)]" would use the Caliburn.Micro Action syntax to enable you to invoke a method on Click event of each button. The $dataContext parameter allows you to pass the corresponding Selected Data Item as parameter to the Method.

    Your ViewModel method would look like

        public void ViewUser(object user)
        {
        // Do work
        }
    

    You can read more on Caliburn.Micro Actions here.