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:

  • Why is the RoutingStrategy on the RoutedEventArgs listed as Direct and not Tunneling? I thought all Preview events were Tunneling.

enter image description here

  • And the more important one: the above solution works if I put a breakpoint inside 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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top