Jul
31
2009

WPF: Changing Input Focus to Hidden Elements



Comments available as RSS 2.0

When trying to change the focused element in the WPF recipe management app I develop, ChickenPing, I recently ran into a problem. I wanted a shortcut key (Ctrl + something) to change the selected tab in a TabControl, then focus an element in that tab. There are a few ways you might try doing this, both do more or less the same thing and both will fail unless the tab in question is already selected. For example:

 tabControl.SelectedItem = someTab;
 someTextBox.Focus();
 FocusManager.SetFocusedElement(this, someTextBox);
 // both only work unless the tab which contains them is visible.

The problem is that an element can only be focused if it is visible. Making the item visible just before trying to focus it fails because the change hasn’t had time to take effect.

After trying different combinations and trawling, I found a method suggested by Mark Smith which used a delegate to wait for an element to load if it was not yet loaded. Taking this idea and using it instead for the IsVisibleChanged event did exactly when I needed.

tabControl.SelectedItem = someTab;
if(!someTextBox.IsVisible) {
    DependencyPropertyChangedEventHandler deferredFocus = null;
    deferredFocus = delegate {
        someTextBox.Focus();
        someTextBox.IsVisibleChanged -= deferredFocus;
    };
    someTextBox.IsVisibleChanged += deferredFocus;
} else {
    someTextBox.Focus();
}

No need to call Dispatcher.Invoke and run into complications with cross-thread access, in my tests it works perfectly.

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay

Comments

  1. cretz says:

    In my opinion, the solution with using the dispatcher invoke is better, because with your solution you have to remember to remove the event handler. The dispatcher code is clean and leaves no “traces” that can affect garbage collection. There is no cross-thread access in your case, because you don’t set the focus from another thread (in that case your solution would not work at all). It’s just delaying the execution of your code until the next layout pass is completed, so that your control is indeed visible.
    The dispatcher offers a way to schedule some code to be executed in the UI thread’s infinite loop (priorities specify where in the loop iteration your code is called).

Leave a Comment

Login using OpenID or enter your details below to leave a comment.

OpenID
Anonymous


Comment

Powered by WP Hashcash