Now basically there are two questions here, let me just gently introduce you to the problem I'm having at the moment. Let's say we have a regular DataGrid, and I try to apply the PreviewMouseRightButtonDown
on the row for custom functionality and at the same time avoid selection, as this expands the Details view. I thought that this post would help; it was directed at ListView
, but with few adjustment it should work the same, right?
Why would you want to do that?, you may ask.
I want to avoid opening the Details on right click, because in the main project Details section makes a (sometimes) lengthy trip to the database, and right-clicking would only set the appropriate bool
flag-property in the view model in collection.
MainWindowView.xaml:
<DataGrid AutoGenerateColumns="False" RowDetailsVisibilityMode="VisibleWhenSelected">
<!-- Columns ommitted for brevity -->
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<!-- Since I'm using Caliburn Micro anyway, I'm going to redirect the event to view model. It doesn't really matter, issue exists with EventSetter too. -->
<Setter Property="cal:Message.Attach" Value="[Event PreviewMouseRightButtonDown] = [Action CheckItem($eventArgs, $source]"/>
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
MainWindowViewModel.cs:
public void CheckItem(RoutedEventArgs args, object source)
{
var row = source as DataGridRow;
if (row != null)
{
var item = (ItemViewModel)row.Item;
item.IsChecked = true;
}
args.Handled = true;
}
Questions time:
RoutingStrategy
on the RoutedEventArgs
listed as
Direct
and not Tunneling
? I thought all Preview
events were
Tunneling
.CheckItem
, selection does not occur and Details are collapsed, everything works
as intended. If I remove the breakpoint though, item is selected and
Details section opens as if the event was not stopped from
propagating. Why does that happen? I thought that setting the
Handled
to true
on the RoutedEventArgs
should just indicate
that the event is really handled.[EDIT]
Now I've found a 'sleazy' workaround, I can just attach the PreviewMouseDown
event:
bool rightClick;
public void MouseDown(object source, MouseEventArgs args)
{
rightClick = false;
if (args.RightButton == MouseButtonState.Pressed)
{
rightClick = true;
//do the checking stuff here
}
}
and then hook up to SelectionChanged
event:
public void SelectionChanged(DataGrid source, SelectionChangedEventArgs args)
{
if (rightClick)
source.SelectedIndex = -1;
}
It works for my particular case, but subjectively looks very smelly, so I'm open to any other suggestions. Especially why the simple eventArgs.Handled = true
on mouse event is not enough to suppress firing of SelectionChanged
later on :)
Handling PreviewMouseRightButtonUp instead of Down gets the desired effect for me (selection must be done on up instead of down?).
The msdn page for PreviewMouseRightButtonDown says its routing strategy should be 'Direct' and the Routed Events Overview page says:
Tunneling events are also sometimes referred to as Preview events, because of a naming convention that is used for the pairs.
So maybe tunneling events are generally preview events, but it doesn't really say that preview events have to be tunneling ;)
Edit:
Looking at the other events like PreviewMouseDown vs MouseDown they are Tunneling and Bubble though, maybe just the Right/Left button events are done as direct.