Click Event not triggered in WPF Datagrid in unallocated row

I have a DataGrid (WPF 4) like this:

<DataGrid Margin="0,0,0,5" VerticalAlignment="Top" Height="192" BorderBrush="#aaa" Background="White" HorizontalAlignment="Left" ItemsSource="{Binding Namen, Mode=OneWay}" ScrollViewer.VerticalScrollBarVisibility="Visible" AutoGenerateColumns="False" ColumnHeaderHeight="24" SelectionChanged="DataGridAuslaendischeAlteNamen_SelectionChanged"> <DataGrid.Columns> <DataGridTextColumn Width="*" Header="Namenseintrag" Binding="{Binding DisplayName, Mode=OneWay}" /> <DataGridTextColumn Width="75" Header="gültig von" Binding="{Binding GueltigAb, StringFormat=d, Mode=OneWay}" /> <DataGridTextColumn Width="75" Header="gültig bis" Binding="{Binding GueltigBis, StringFormat=d., Mode=OneWay}" /> <DataGridTemplateColumn Width="20" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Style="{DynamicResource CaratRemoveButton}" Click="Button_Click" CommandParameter="{Binding}" PreviewMouseDown="Button_PreviewMouseDown" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> 

The problem I am experiencing is that the DataGridTemplateColumn button does not fire the click-event event if its row is not selected. Therefore, I have to click the button twice, once, to select its row, and then raise the click event. I read about similar issues with checkbox columns, but it was obvious there that you needed to use a template column. I tested using the PreviewMouseDown-Event button, which works, but that’s not what I want, since then the button does not follow a regular graphic click.

What am I missing here? How can I get this click event by simply clicking once, regardless of whether the row was selected or not?

+6
source share
6 answers

Basically, you have no solution other than using the TemplateColumn and managing each individual mouse user.

Explanation:

click = mouseDown + MouseUp , on the right. therefore, your button should be able to receive the mouseDown + MouseUp event.

BUT...

by default, wpf DataGrid has its own rows that handle the mouseDown event to select the one you use mouseDown on (to confirm: mouseDown on the cell and hold the mouse button, you will see that the row is selected before you release the button).

So basically, MouseDownEvent processed before it reaches the button, which allows you to use the Click event on the button

Microsoft will tell us in its document that in such cases we should refer to the preview event, but this cannot be applied to the click event, since you cannot have PreviewClickEvent

So, the only solution that I see for you is to listen to both PreviewMouseDown and PreviewMouseUp on your button and simulate the click yourself.

something like that:

 Button myButton = new Button(); bool mouseLeftButtonDownOnMyButton; myButton.PreviewMouseLeftButtonDown += (s, e) => { mouseLeftButtonDownOnMyButton = true; }; myButton.PreviewMouseLeftButtonUp += (s, e) => { if (mouseLeftButtonDownOnMyButton) myButton.RaiseEvent( new RoutedEventArgs(Button.ClickEvent,myButton)); mouseLeftButtonDownOnMyButton = false; }; myButton.Click += myButtonCLickHandler; 

(of course you need to translate this into your xaml template)

NB: this is not complete, you should also take care of cases when the user makes mouseDown on the button, but moves the mouse out of the button before making a hint (in this case, you must reset the mouseLeftButtonDownOnMyButton flag). The best way would probably be to reset the flag in the general mouseUpEvent (e.g. at window level) rather than in a single button.

Edit: the above code also allows you to control the Click event and have only one code for real and simulated click events (hence the RaiseEvent method), but if you need it, you can also specify your code directly in the PreviewMouseUp section.

+8
source

I had the same problem - I used Image on Column Column and had an event on MouseDown, but I had to double-click. So I called the event handler on the constructor, and it worked for me.

You can try the following:

 constructor() { datagridname.AddHandler(Button.ClickEvent, new RoutedEventHandler(Button_Click), true); } 
0
source

Another solution would be to create your own button. One of the advantages of this: you do not need to connect events for each button.

 public class FireOnPreviewButton : Button { #region Constructor public FireOnPreviewButton() { PreviewMouseLeftButtonDown += OnLeftMouseButtonDownPreview; } #endregion #region Event Handler private void OnLeftMouseButtonDownPreview(object sender, MouseButtonEventArgs e) { // Prevent the event from going further e.Handled = true; // Invoke a click event on the button var peer = new ButtonAutomationPeer(this); var invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider; if (invokeProv != null) invokeProv.Invoke(); } #endregion } 
0
source

This may not be for you, but the setting for IsReadonly = true has been resolved for me.

0
source

I understand this question is old, but I am under a 10 year contract that uses WPF and XAML, and I ran into the same problem where users had to double-click a row in the DataGrid to activate the mouse button event. This is because the dataset consumes the first click to select a row and the second click to trigger an event. I found a much simpler solution that works for my application:

  PreviewMouseLeftButtonDown="MainDataGrid_OnMouseLeftButtonDown" 

This causes the first mouse click with the left mouse button. Here's what it looks like in a datagrid setup:

  <DataGrid Name="MainDataGrid" IsSynchronizedWithCurrentItem="True" SelectionMode="Extended" SelectionUnit="FullRow" ...removed other options for brevity PreviewMouseLeftButtonDown="MainDataGrid_OnMouseLeftButtonDown" ...removed other options for brevity RowHeight="30" BorderThickness="0" Background="#99F0F0F0" Grid.Column="{Binding GridColumn, Mode=TwoWay}" Grid.Row="1"> 

I used this instead of MouseLeftButtonDown. Greetings.

0
source

It is too late, but not for others.

I ran into the same problem and spent almost 6 hours to find a workaround. I don’t want anyone to waste time again. Seeing all possible answers. Here is how I fixed it:

I associated the method with the main / parent event of the DataGrid Loaded . Method Definition:

 private void FrameworkElement_OnLoaded(object sender, RoutedEventArgs e) { var grid = sender as DataGrid; if (grid != null && grid.CurrentItem == null && grid.SelectedItem != null) { grid.CurrentItem = grid.SelectedItem; } else if (grid != null) //Fix when IsSynchronizedWithCurrentItem=True { var selectedItem = grid.SelectedItem; grid.CurrentItem = null; grid.SelectedItem = null; grid.CurrentItem = selectedItem; grid.SelectedItem = selectedItem; } } 
0
source

Source: https://habr.com/ru/post/903376/


All Articles