views:

400

answers:

2

I've done a lot of searching on SO and google around this problem, but can't seem to find anything else to try.

I have a MainView (window) that contains a tab control. The tab control binds to an ObservableCollection of ChildViews (user controls). The MainView's ViewModel has a method that allows adding to the collection of ChildViews, which then creates a new tab. When a new tab is created, it becomes the active tab, and this works fine. This method on the MainView is called from another ViewModel (OtherViewModel).

What I am trying to do is set the keyboard focus to the first control on the tab (an AutoCompleteBox from WPFToolkit*) when a new tab is created. I also need to set the focus the same way, but WITHOUT creating a new tab (so set the focus on the currently active tab).

(*Note that there seem to be some focus problems with the AutoCompleteBox--even if it does have focus you need to send a MoveNext() to it to get the cursor in its window. I have worked around this already).

So here's the problem. The focusing works when I don't create a new tab, but it doesn't work when I do create a new tab. Both functions use the same method to set focus, but the create logic first calls the method that creates a new tab and sets it to active. Code that sets the focus (in the ChildView's Codebehind):

        IInputElement element1 = Keyboard.Focus(autoCompleteBox);
        //plus code to deal with AutoCompleteBox as noted.

In either case, the Keyboard.FocusedElement starts out as the MainView. After a create, calling Keyboard.Focus seems to do nothing (focused element is still the MainView). Calling this without creating a tab correctly sets the keyboard focus to autoCompleteBox.

Any ideas?

Update:

Bender's suggestion half-worked.

So now in both cases, the focused element is correctly the AutoCompleteBox. What I then do is MoveNext(), which sets the focus to a TextBox. I have been assuming that this Textbox is internal to the AutoCompleteBox, as the focus was correctly set on screen when this happened. Now I'm not so sure. This is still the behavior I see when this code gets hit when NOT doing a create. After a create, MoveNext() sets the focus to an element back in my MainView.

The problem must still be along the lines of Bender's answer, where the state of the controls is not the same depending on whether a new tab was created or not. Any other thoughts?

Final Update

As noted, majocha's suggestion worked.

I wanted to update this in case anyone happened upon this same problem with the AutoCompleteBox. It appears that setting focus does not activate it in the UI--you need to do a MoveNext on it to move focus forward once to the control's internal Textbox. This is based on my debugging experience, which may not be 100% scientific. If I have time, I will attempt to create a small repro project and submit it to the WPFToolkit team.

+1  A: 

The control must be visible to be focused, you may try to defer focusing by subscribing to the IsVisibleChanged event, something similar to the following should work:

public static void setFocusLate(this Control control)
        {
            DependencyPropertyChangedEventHandler handler = null;

            handler = delegate
                {
                    control.Focus();
                    control.IsVisibleChanged -= handler;
                };

            control.IsVisibleChanged += handler;
        }
Armin
Thanks for your answer. See my update if you get a chance.
Phil Sandler
+2  A: 

You can try defering the focus change with

Dispatcher.BeginInvoke(MyChangeFocusAction, DispatcherPriority.ContextIdle);

It will get queued after layout and properties updates are done. I don't think it's best practice, but it works for me.

majocha
That worked! Thanks for your help.
Phil Sandler