Change Focus Behavior

Hi Walter,
I have a little problem. In my Diagram I have some Buttons and some Sliders. If I start the program and press the arrow keys on the keyboard the diagram is moving as excepted. Then I added some nodes (programatically) and after that I press the arrow keys again - now a Slider gets focus automatically and I can change it’s value with the keyboard. But I don’t want a Slider, that I don’t have clicked before, to get the focused node!
How can I prevent the behavior?

I am guessing that your diagram lost focus when the user caused those programmatic changes to happen.

Try explicitly giving focus back to the diagram.

I’ve tried that - but nothing changes.
If I click an empty space in the diagram and press arrow keys the diagram is moving again. But every time I change something in the nodesource I have the behavior.

If I doesn’t find the issue, the only possibility that I see is to make the slider ignore keyboard events which would be too bad.

When and how did you give focus to the diagram? And when and how did it lose focus?

I set Diagram.Focus() immediately after adding and deleting nodes from the diagram.
But I have no idea when it goes away. Fact is that the diagram is keeping the focus until I click any node or I call the method to add and/or delete nodes.
I first thought, that I always delete the node which has actual focus - but that’s not the case.

In searching the sources of all of the samples that I have, there are several times when the code does call myDiagram.Focus() in order to make sure the Diagram gets back focus because the user clicked on some Button or because the user did a drag-and-drop from a Palette to a Diagram and the code wanted to make sure that the focus is in the target Diagram, not in the source Diagram/Palette.

You should know what is causing loss of focus. Unless your code is programmatically changing focus, it should be obvious what the user just did. And it is generally preferred not to have focus changes happening programmatically, which is why there are so few such calls in all of our samples.

The only place I set Focus to the diagram directly is in ExterObjectsDropped-Handler. No one else.
The other one I mentioned earlier was just for testing.
I could make a little video if you are interested.

But what does the user do to cause nodes to be added or removed? Doesn’t that cause the focus to change?

Oh of course. The user clicks on a button, that causes the method call to change the nodes.

My guess is that when the diagram gets focus (without a explicit click) it predicts focus to one of it’s child controls.
Maybe it’s a WPF issue?

I haven’t checked, but I don’t think that is the problem.

The implementation of ToolManager.DoMouseDown calls this.Diagram.Focus();.

This is a view of the application. With the two buttons on the right the user can switch to another set of sliders and volumemeters.
But when the user is pressing the arrow keys on the keyboard one of the sliders got focus (without any click) and the buttons where moving the thumb of the slider. That’s an expected behavor when the user has clicked the slider before! But not if whoever is selecting a random slider.

I just tried a sample where each Node has some Buttons. Clicking in the background of the Diagram seems to give focus to the Diagram, not to any Button within any of the Nodes.

Hitting the TAB key does change focus to cycle through the Buttons.

Did you really want to support the arrow keys scrolling the diagram? You could either remove the InputBindings for the arrow keys, or implement a Diagram.PreviewKeyDown handler that sets e.Handled = true.

Ok, this will prevent the sliders from getting focused, but it also prevents them from being adjusted with the arrow keys - which is nice when you previously select the slider.

In the PreviewKeyDown of the Diagram I have the following code:

if (e.Key == Key.Down || e.Key == Key.Up || e.Key == Key.Right || e.Key == Key.Left)
{
    int changePositionRange = 1;
    if (DiagramInView.GridSnapEnabled)
    {
        changePositionRange = (int) DiagramInView.GridSnapCellSize.Width;
    }

    if ((Keyboard.Modifiers & ModifierKeys.Control) > 0)
    {
        changePositionRange = 10;
    }

    if (!DiagramInView.SelectedParts.Any()) return;

    DiagramInView.StartTransaction("move selection");
    foreach (Part part in DiagramInView.SelectedParts)
    {
        Node n = part as Node;
        if (n == null) continue;

        Point pos = n.Position;
        switch (e.Key)
        {
            case Key.Down:
                n.Move(new Point(pos.X, pos.Y + changePositionRange), false);
                break;
            case Key.Up:
                n.Move(new Point(pos.X, pos.Y - changePositionRange), false);
                break;
            case Key.Right:
                n.Move(new Point(pos.X + changePositionRange, pos.Y), false);
                break;
            case Key.Left:
                n.Move(new Point(pos.X - changePositionRange, pos.Y), false);
                break;
        }
    }
    DiagramInView.CommitTransaction("move selection");
}

Is there something that may course the focus change?
It’s the PreviewKeyPressCommand in the ViewModel and the DiagramInView is the Diagram.

Well, since you have not set e.Handled, the regular behavior for that particular key could be causing the focus change.

Do you know if

KeyboardNavigation.TabNavigation = "Local"

or

KeyboardNavigation.DirectionalNavigation="None"

could help? And where to set it (Diagram or Control)?

I haven’t tried that in a decade. I would try setting that either on the Diagram or on the DiagramPanel.

In the meantime I tried the different KeyboardNavigation Settings some made it worse the others doesn’t change the behavior.
Now I do massiv checks in the KeyDownCommand. The Silders are working as expected (react to the arrow keys only if clicked previously), but to reach this goal the Diagram isn’t moving with the keys (that’s a pity but apparently I can not prevent it - every time the diagram reacts to the keys and no node has the focus, it selects a Slider based on the TabOrder).
I can live with that - hopefully my customers can!