I am using Caliburn Micro and Dapper in a WPF Project where I create a DataGrid
which I populate with data from a SQL Server Database Table. Please consider the following code snippets:
ChangesModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PTSRDesktopUI.Models
{
//public class for all changes attributes
public class ChangesModel
{
public int ID { get; set; }
public string Facility { get; set; }
public string Controller { get; set; }
public string ParameterName { get; set; }
public string OldValue { get; set; }
public string NewValue { get; set; }
public DateTime ChangeDate { get; set; }
public bool Validated { get; set; }
public DateTime ValidationDate { get; set; }
}
}
OverviewView.xaml
<!--Datagrid Table-->
<DataGrid Grid.Row="1" x:Name="Changes" CanUserAddRows="False" AutoGenerateColumns="False" HorizontalAlignment="Stretch">
<DataGrid.Columns>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True"
Header="Facility" Binding="{Binding Path=Facility}"/>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True"
Header="Controller" Binding="{Binding Path=Controller}"/>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True"
Header="Parameter" Binding="{Binding Path=ParameterName}"/>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True"
Header="Old Value" Binding="{Binding Path=OldValue}"/>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True"
Header="New Value" Binding="{Binding Path=NewValue}"/>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True"
Header="Changed Date" Binding="{Binding Path=ChangeDate,
StringFormat='{}{0:dd.MM HH:mm}'}"/>
<DataGridTemplateColumn CellStyle="{StaticResource DataGridCellCentered}"
Header="Validated" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate >
<CheckBox IsChecked="{Binding Path=Validated}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn CellStyle="{StaticResource DataGridCellCentered}" IsReadOnly="True"
Header="Validation Date" Binding="{Binding Path=ValidationDate,
StringFormat='{}{0:dd.MM HH:mm}'}"/>
<DataGridTemplateColumn CellStyle="{StaticResource DataGridCellCentered}" Header="Validate">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="Validate_Btn" cal:Message.Attach="Validate">Validate</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
OverviewViewModel.cs
using Caliburn.Micro;
using PTSRDesktopUI.Helpers;
using PTSRDesktopUI.Models;
namespace PTSRDesktopUI.ViewModels
{
public class OverviewViewModel : Screen
{
//Create new Bindable Collection variable of type ChangesModel
public BindableCollection<ChangesModel> Changes { get; set; }
public OverviewViewModel()
{
//Create connection to DataAccess class
DataAccess db = new DataAccess();
//get the changes from DataAccess function and store them as a bindable collection in Changes
Changes = new BindableCollection<ChangesModel>(db.GetChanges());
}
//Validate_Btn click event
public void Validate()
{
//Some Code
}
}
}
DataAccess.cs
//Function to get all changes from database using stored procedures
public List<ChangesModel> GetChanges()
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(DBHelper.CnnVal("ptsrDB")))
{
var output = connection.Query<ChangesModel>("dbo.getChanges").ToList();
return output;
}
}
I use a stored procedure called getChanges
to get the data from the SQL Server. The data is displayed and it all works fine. What I want to do now is this:
Firstly I want the Validate_Btn
to only be visible on rows where the CheckBox
is unchecked. Secondly, if the user clicks the Validate_Btn
, I want to change the CheckBox
to checked, make the button invisible and trigger a new function with a stored procedure from the DataAccess class to update the boolean value for Validated
in the database table. Anyone have any ideas how I could do this?
To solve the first part of displaying and hiding the Button
based on whether the CheckBox
is checked, you should first implement the INotifyPropertyChanged interface in your ChangesModel
class and raise the PropertyChanged
event when the Validated
property is set:
public class ChangesModel : INotifyPropertyChanged
{
public int ID { get; set; }
public string Facility { get; set; }
public string Controller { get; set; }
public string ParameterName { get; set; }
public string OldValue { get; set; }
public string NewValue { get; set; }
public DateTime ChangeDate { get; set; }
private bool _validated;
public bool Validated
{
get { return _validated; }
set { _validated = value; NotifyPropertyChanged(); }
}
public DateTime ValidationDate { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
You could then bind the Button
's Visibility
property to the Validated
source property and use a converter to convert between the bool
value and a Visibility
enumeration value:
<DataGridTemplateColumn Header="Validate">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DataTemplate.Resources>
<BooleanToVisibilityConverter x:Key="converter" />
</DataTemplate.Resources>
<Button x:Name="Validate_Btn" cal:Message.Attach="Validate"
Visibility="{Binding Validated, Converter={StaticResource converter}}">Validate</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
You may also want to set the UpdateSourcePropertyTrigger
on the CheckBox
binding for the source property to be set immediately:
<CheckBox IsChecked="{Binding Path=Validated, UpdateSourceTrigger=PropertyChanged}" />
For your Validate()
to get called when you click the button, you could bind the Bind.Model
attached property to the view model:
<Button x:Name="Validate"
cal:Bind.Model="{Binding DataContext,
RelativeSource={RelativeSource AncestorType=DataGrid}}">Validate</Button>
Combining the bindings requires to specify a source of the Visibility
binding:
<Button x:Name="Validate"
Visibility="{Binding DataContext.Validated,
Converter={StaticResource converter}, RelativeSource={RelativeSource AncestorType=DataGridCell}}"
cal:Bind.Model="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}">Validate</Button>