I'm building a POS application, and I want the end user to be able to have a toggle selection mode for the datagrid, I.E. they can click on multiple rows and each clicked item will accumulate on the SelectedItems property - also clicking on a row that was already selected will deselect the row. I found this code in another stackoverflow question:
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="DoCheckRow" />
</Style>
</DataGrid.Resources>
public void DoCheckRow(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing)
{
DataGridRow row = VisualHelpers.TryFindParent<DataGridRow>(cell);
if (row != null)
{
row.IsSelected = !row.IsSelected;
e.Handled = true;
Debug.WriteLine(sender);
}
}
}
That effectively gives me what I want as far as the toggle selection mode, however, when I add a button as a CellTemplate, the buttons command isn't fired when clicked because I'm setting e.Handled = true;
in the above code which stops the event bubble. Is there a way that I can accommodate both?
I was able to solve it by using some helper functions to find the visual child / parent and some hit testing:
public void DoCheckRow(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing)
{
DataGridRow row = VisualHelpers.TryFindParent<DataGridRow>(cell);
if (row != null)
{
Button button = VisualHelpers.FindVisualChild<Button>(cell, "ViewButton");
if (button != null)
{
HitTestResult result = VisualTreeHelper.HitTest(button, e.GetPosition(cell));
if (result != null)
{
// execute button and do not select / deselect row
button.Command.Execute(row.DataContext);
e.Handled = true;
return;
}
}
row.IsSelected = !row.IsSelected;
e.Handled = true;
}
}
}
Granted its not the most elegant solution, but it works with the MVVM pattern that I use.