seanzi
seanzi

Reputation: 883

wpf RowDetailsTemplate focus

I currently have a datagrid with a rowdetailstemplate which contains another datagrid to show a parent to child relationship. The second grid has a column which contains a button which when clicked displays another dialog.

The first time the details for a row are displayed, the user has to click once in the child grid to gain focus/activate it and then click again to fire the button click event. This only happens the first time a row is shown.

It is like the first click is swallowed by the grid. I have tried capturing the RowDetailsVisibilityChanged event to try and focus the button but it still doesn't seem to have solved the issue.

Any ideas?

Upvotes: 5

Views: 2932

Answers (3)

c4rl2s0n
c4rl2s0n

Reputation: 1

This is my first post here, so I cannot comment...

Since this was driving me crazy for a while I wanted to add a line to Samuels answer (which is actually a great solution).

I had the problem, that I could not select items from a ComboBox inside the DetailsView, because the focus was always set to the DataGridRow, so to avoid re-focusing and make the solution more stable, I added the check

if(row.IsKeyboardFocusWithin) return;

So the complete Code looks like this:

private void SelectRowDetails(object sender, MouseButtonEventArgs e)
{
    var row = sender as DataGridRow;
    if (row == null || row.IsKeyboardFocusWithin)
    {
        return;
    }
    row.Focusable = true;
    row.Focus();

    var focusDirection = FocusNavigationDirection.Next;
    var request = new TraversalRequest(focusDirection);
    var elementWithFocus = Keyboard.FocusedElement as UIElement;
    if (elementWithFocus != null)
    {
        elementWithFocus.MoveFocus(request);
    }
}

Upvotes: 0

Ashi
Ashi

Reputation: 864

I found a good solution :D

I have one line of code that solves this problem but 10 lines to describe what is the problem. Here is the solution:

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        // to stop RowDetails from eating the first click.
        if (e.Property.Name == "SelectedItem" && CurrentItem == null) CurrentItem = SelectedItem;
    }

AND Find the details here please.

Upvotes: 1

Samuel
Samuel

Reputation: 6490

I'll answer my own comment and it probably helps others too. The following MSDN entry explains and solves the issue: http://social.msdn.microsoft.com/Forums/vstudio/en-US/2cde5655-4b8d-4a12-8365-bb0e4a93546f/activating-input-controls-inside-datagrids-rowdetailstemplate-with-single-click?forum=wpf

The problem is that a row details that is always shown requires gaining the focus first. To circumvent that problem a datagrid preview handler is required:

<DataGrid.RowStyle>
    <Style TargetType="{x:Type DataGridRow}"  BasedOn="{StaticResource {x:Type DataGridRow}}">
        <EventSetter Event="PreviewMouseLeftButtonDown" Handler="SelectRowDetails"/>
    </Style>
</DataGrid.RowStyle>

Note: I've extended it as it destroyed my custom DataGridRow Style to inherit the currently used one.

The handler itself is

private void SelectRowDetails(object sender, MouseButtonEventArgs e)
{
    var row = sender as DataGridRow;
    if (row == null)
    {
        return;
    }
    row.Focusable = true;
    row.Focus();

    var focusDirection = FocusNavigationDirection.Next;
    var request = new TraversalRequest(focusDirection);
    var elementWithFocus = Keyboard.FocusedElement as UIElement;
    if (elementWithFocus != null)
    {
        elementWithFocus.MoveFocus(request);
    }
}

It sets the focus to the content of the row details, which solves the click-twice issue.

Note: This all taken from the MSDN thread, it is not my own solution.

Upvotes: 6

Related Questions