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