views:

36

answers:

2

I have been putting off activity on SO because my current reputation is "1337". :)

This is a question of "why" and not "how". By default, it seems that WPF does not set focus to the first control in a window when it's opening. In addition, when a textbox gets focus, by default it does not have it's existing text selected. So basically when I open a window, I want focus on the first control of the window, and if that control is a textbox, I want it's existing text (if any) to be selected.

I found some tips online to accomplish each of these behaviors, and combined them. The code below, which I placed in the constructor of my window, is what I came up with:

Loaded += (sender, e) =>
          {
              MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
              var textBox = FocusManager.GetFocusedElement(this) as TextBox;
              if (textBox != null)
              {
                  Action select = textBox.SelectAll;
                  //for some reason this doesn't work without using invoke.
                  Dispatcher.Invoke(DispatcherPriority.Loaded, select);
              }
          };

So, my question. Why does the above not work without using Dispatcher.Invoke? Is something built into the behavior of the window (or textbox) cause the selected text to be de-selected post-loading?

Maybe related, maybe not--another example of where I had to use Dispatcher.Invoke to control the behavior of a form:

http://stackoverflow.com/questions/2602979/wpf-focus-in-tab-control-content-when-new-tab-is-created

+1  A: 

All WPF controls have thread affinity. The Dispatcher manages the thread that each control was created on (typically this is a single thread for every control in the application, but not necessarily). Work is queued on this thread and executed in priority order.

Any UI-manipulating code has to be executed on the same thread as the control was created on - the Dispatcher thread - and so any method has to invoke back to that thread before it can do anything that would affect the UI (such as selecting text in the TextBox).

That said, it's my understanding that the Loaded eventhandler would fire on the Dispatcher thread by default, so I'm not entirely sure why you're seeing this behaviour in your specific example!

Dan Puzey
+1  A: 

I should start by mentioning i had no issues making that work w/ out the dispatcher call in .net 4.0 (it may have been fixed in the framework update)- however, what the previous poster mentioned is accurate and has been the pardigm since the dawn of winforms (.DoActions() and .Invoke()). However, in 3.5 the above did work w/ out dispatcher if you use a method defined in the codebehind as the target call in your lambda:

  Loaded += (sender, e) =>
  {
   this.SelectText();
  };  

  void SelectText()
  {
   MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
   var textBox = FocusManager.GetFocusedElement(this) as TextBox;

   if (textBox != null)
   {
    textBox.SelectAll();
   }
  }

As to why, I cant really give you the specifics but I've run into similar issues w/ using lambdas to route events on presenters. I want to say its something to do w/ reference or context of the compiled expression- in this case it needs a ref to the containing object in order to know how to delegate the operation (selecting the textbox text on the right thread). I also believe that GC can occasionally clean up resources so deferred execution gets botched (seen it in F#...believed that was the cause of my issue in C# as well).

J Rothe