General question about WPF control style and using Invoke

I am postponing activity on SO because my current reputation is "1337". :)

This is a question of "why", not "how". By default, WPF seems to not set focus to the first control in a window when it is opened. Also, when a text box receives focus, it has no existing text by default. So when I open the window, I want to focus on the first control of the window, and if that control is a textbox, I want it to be the existing text (if any).

I found some tips on the internet to accomplish each of these behaviors and combine them. The code below that I posted in my window constructor 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 is. Why doesn't the above work without using Dispatcher.Invoke? Is something built into the behavior of the window (or textbox) causing the selected text to be canceled after loading?

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

WPF Focus In Tab Content Control When New Tab Is Created

+2


a source to share


2 answers


All WPF controls have thread affinity. Dispatcher

controls the thread on which each control was created (usually one thread for each control in the application, but not required). Work is queued on this thread and executed in order of priority.

Any UI manipulation code must run on the same thread that the control was created on Dispatcher

, and so any method must return to that thread before it can do anything that affects the UI (such as text selection c TextBox

).



However, I understand that the event handler Loaded

started the Dispatcher thread by default, so I'm not entirely sure why you are seeing this behavior in your specific example!

+1


a source


I have to start by mentioning that I had no problem with this working not working with dispatch call in .net 4.0 (it may have been fixed in a framework update), however what was mentioned in the previous post was accurate and there was pardigm from the start of winforms (.DoActions () and .Invoke ()). However, in 3.5 above, worked without a dispatcher if you use a method defined in code 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 for why, I cannot give you specifics, but I ran into similar problems using lambdas to route events to presenters. What I mean is that it has something to do with the link or the context of the compiled expression - in which case it needs a reference to the contained object to know how to delegate the operation (selecting the text of the textbox on the right stream). I also believe that the GC can clean up resources sometimes, so lazy execution breaks (you can see that in F # ... I believe this is what caused my problem in C #).

+1


a source







All Articles