我一直在推迟SO的活动,因为我目前的名声是“1337”。 :)
这是“为什么”而不是“如何”的问题。默认情况下,似乎WPF在窗口打开时没有将焦点设置到窗口中的第一个控件。此外,当文本框获得焦点时,默认情况下它不会选择现有文本。所以基本上当我打开一个窗口时,我想要专注于窗口的第一个控件,如果该控件是一个文本框,我想要它的现有文本(如果有的话)被选中。
我在网上找到了一些完成这些行为的技巧,并将它们结合起来。我在窗口的构造函数中放置的代码就是我想出的代码:
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);
}
};
所以,我的问题。为什么上面不使用Dispatcher.Invoke不起作用?是否内置于窗口(或文本框)的行为中导致所选文本在加载后取消选择?
也许相关,也许不是 - 我必须使用Dispatcher.Invoke来控制表单行为的另一个例子:
答案 0 :(得分:1)
所有WPF控件都具有线程关联性。 Dispatcher
管理创建每个控件的线程(通常这是应用程序中每个控件的单个线程,但不一定)。工作在此线程上排队并按优先级顺序执行。
任何UI操作代码必须在与Dispatcher
线程上创建控件的同一线程上执行 - 因此任何方法都必须先调用回该线程,然后才能执行任何可能影响的操作用户界面(例如在TextBox
中选择文字)。
那就是说,我的理解是默认情况下Loaded
事件处理程序会在Dispatcher线程上触发,所以我不完全确定你为什么会在你的具体例子中看到这种行为!
答案 1 :(得分:1)
我首先要提到的是,我没有任何问题可以在.net 4.0的调度员调用中完成这项工作(它可能已在框架更新中得到修复) - 但是,之前的海报所提到的是准确的并且一直是自winforms曙光(.DoActions()和.Invoke())以来的pardigm。但是,在3.5中,如果你使用codebehind中定义的方法作为lambda中的目标调用,那么上面的工作将完成w / out调度程序:
Loaded += (sender, e) =>
{
this.SelectText();
};
void SelectText()
{
MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
var textBox = FocusManager.GetFocusedElement(this) as TextBox;
if (textBox != null)
{
textBox.SelectAll();
}
}
至于为什么,我真的不能给你具体细节,但我遇到了类似的问题w /使用lambdas在演示者上路由事件。我想说一下w / reference或编译表达式的上下文要做的事情 - 在这种情况下,它需要对包含对象的引用,以便知道如何委托操作(在右侧线程上选择文本框文本)。我也相信GC偶尔可以清理资源,因此延迟执行会变得很拙劣(在F#中看到它......认为这也是我在C#中出现问题的原因)。