无法将焦点设置为UserControl的子项
我有一个UserControl
,其中包含一个TextBox
。 当我的主窗口加载我想设置焦点到这个文本框,所以我添加焦点Focusable="True" GotFocus="UC_GotFocus"
到UserControl
的定义和FocusManager.FocusedElement="{Binding ElementName=login}"
我的主窗口定义。 在UC_GotFocus
方法中,我只是简单地调用我想要关注的控件上的.Focus()
,但这不起作用。
我所需要做的是在应用程序启动时在UserControl
接收焦点中有一个TextBox
。
任何帮助将不胜感激,谢谢。
我最近解决了这个问题,当初次加载主窗口时,通过故事板显示login启animation面。
我相信有两个关键的修复。 一个是使包含元素的焦点范围。 另一个是处理由被加载的窗口触发的故事板的Storyboard Completed事件。
这个故事板使用户名和密码canvas可见,然后淡入到100%不透明。 关键是用户名控制在故事板运行之前是不可见的,因此只有当控制台可见时才能获得键盘焦点。 是什么让我停下来了一段时间,它有“专注”(即重点是真实的,但事实certificate,这只是合乎逻辑的重点),我不知道WPF有逻辑和键盘焦点的概念,直到阅读Kent Boogaart的回答并查看微软的WPF 链接文本
一旦我这样做,解决我的特定问题很简单:
1)使包含的元素成为焦点范围
<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed"> <TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False"> </TextBox> </Canvas>
2)将一个完成的事件处理程序附加到故事板
<Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed"> ... </Storyboard>
和
3)将我的用户名文本框设置为在故事板完成的事件处理程序中具有键盘焦点。
void UserNamePassword_Storyboard_Completed(object sender, EventArgs e) { m_uxUsername.Focus(); }
请注意,调用item.Focus()会导致调用Keyboard.Focus(this),所以不需要明确地调用它。 看到这个问题关于Keyboard.Focus(item)和item.Focus之间的区别。
它的愚蠢,但它的作品:
popup等待一段时间的线程,然后返回并设置所需的焦点。 它甚至可以在元素主机的上下文中工作。
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e) { System.Threading.ThreadPool.QueueUserWorkItem( (a) => { System.Threading.Thread.Sleep(100); someUiElementThatWantsFocus.Dispatcher.Invoke( new Action(() => { someUiElementThatWantsFocus.Focus(); })); } ); }
就在最近我有一个列表框,里面放置了一些TextBlocks。 我希望能够双击文本块,并将它变成一个文本框,然后将其集中并select所有文本,以便用户可以开始键入新名称(类似于Adobe图层)
无论如何,我正在做一个事件,它只是不工作。 对我来说,这里的魔力就是确保我设置事件来处理。 我认为这是重点,但是一旦事件走下坡路,就会转变逻辑重点。
故事的寓意是,确保你将事件标记为已处理,这可能是你的问题。
“在应用程序启动时设置初始焦点时,要接收焦点的元素必须连接到PresentationSource,并且该元素必须将Focusable和IsVisible设置为true。 build议初始焦点的位置在“Loaded事件处理程序”(MSDN)
只需在Window(或Control)的构造函数中添加一个“Loaded”事件处理程序,然后在该事件处理程序中调用目标控件上的Focus()方法。
public MyWindow() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MyWindow_Loaded); } void MyWindow_Loaded(object sender, RoutedEventArgs e) { textBox.Focus(); }
因为我尝试了一个fuzquat的解决scheme,并发现它是最通用的,我想我会分享一个不同的版本,因为有些抱怨看起来很混乱。 所以这里是:
casted.Dispatcher.BeginInvoke(new Action<UIElement>(x => { x.Focus(); }), DispatcherPriority.ApplicationIdle, casted);
没有Thread.Sleep,没有ThreadPool。 干净,我希望。 真的可以使用一些代表,所以我可以评论其他人民的解决scheme。
更新:
由于人们似乎喜欢漂亮的代码:
public static class WpfExtensions { public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement { element.Dispatcher.BeginInvoke(priority, action); } }
现在你可以这样称呼它:
child.BeginInvoke(d => d.Focus());
我发现了一系列关于WPF焦点的博文。
- 第一部分:基本上是重点
- 第2部分:在代码中更改WPF焦点
- 第3部分:将焦点转移到WPF中的第一个可用元素
它们都很好阅读,但第三部分专门处理将焦点设置到UserControl中的UI元素。
- 将您的用户控件设置为Focusable =“True” (XAML)
- 在你的控件上处理GotFocus事件并调用你的TextBox.Focus()
- 处理窗口上的Loaded事件并调用yourControl.Focus()
我有一个示例应用程序运行此解决scheme,因为我键入。 如果这不适用于您,那么您的应用程序或环境中必须有特定的东西来解决问题。 在你原来的问题中,我认为绑定导致了这个问题。 我希望这有帮助。
WPF支持两种不同的焦点:
- 键盘焦点
- 逻辑的重点
FocusedElement
属性获取或设置焦点范围内的逻辑焦点。 我怀疑你的TextBox
确实有逻辑焦点,但是它包含的焦点范围不是活动焦点范围。 Ergo,它没有键盘焦点。
所以问题是,你的视觉树中有多个焦点范围?
我注意到一个焦点问题,具体涉及到托pipe在ElementHosts内的WPF UserControls包含在通过MdiParent属性设置为一个MDI子窗体中。
我不确定这是否与其他人遇到的问题相同,但您可以通过以下链接深入了解详细信息。
在WindowsForms子MDI表单中的ElementHost中承载的WPF UserControl中设置焦点的问题
在“WPF初始焦点梦魇”之后,根据堆栈上的一些答案,以下certificate对我来说是最好的解决scheme。
首先,添加你的App.xaml的OnStartup()如下:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent, new RoutedEventHandler(WindowLoaded));
然后在App.xaml中添加“WindowLoaded”事件:
void WindowLoaded(object sender, RoutedEventArgs e) { var window = e.Source as Window; System.Threading.Thread.Sleep(100); window.Dispatcher.Invoke( new Action(() => { window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); })); }
线程问题必须使用,因为WPF的初始焦点大多因为一些框架竞争条件而失败。
我发现以下解决scheme是最好的,因为它是全球使用整个应用程序。
希望能帮助到你…
奥兰
我的技巧是什么FocusManager.FocusedElement属性。 我第一次尝试将其设置在UserControl上,但它不起作用。
所以我试着把它放在UserControl的第一个孩子上:
<UserControl x:Class="WpfApplication3.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}"> <TextBox x:Name="MyTextBox"/> </Grid>
…它的工作! 🙂
我将fuzquat的答案转换为扩展方法。 我正在使用这个而不是焦点()在焦点()没有工作。
using System; using System.Threading; using System.Windows; namespace YourProject.Extensions { public static class UIElementExtension { public static void WaitAndFocus(this UIElement element, int ms = 100) { ThreadPool.QueueUserWorkItem(f => { Thread.Sleep(ms); element.Dispatcher.Invoke(new Action(() => { element.Focus(); })); }); } } }
我有用户控制 – 有两个文本框的堆栈面板。文本框被添加到构造函数中,而不是在xaml中。 当我试图把重点放在第一个文本框,什么都没有发生。 加载事件的信号处理修复了我的问题。 只需在加载的事件中调用control.Focus()。
假设您要为用户名文本框设置焦点,用户可以在每次显示时直接input。
在你的控件的构造函数中:
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
尝试了上述build议的组合后,我能够可靠地将焦点分配给子控件UserControl上的所需文本框,其中包含以下内容。 基本上,把重点放在子控件上,并让子控件UserControl把焦点放到它的TextBox上。 TextBox的焦点语句本身返回true,但直到UserControl被赋予焦点之后才产生所需的结果。 我还应该注意到UserControl无法为自己请求焦点,并且必须由Window给出。
为了简洁起见,我忽略了在Window和UserControl上注册Loaded事件。
窗口
private void OnWindowLoaded(object sender, RoutedEventArgs e) { ControlXYZ.Focus(); }
用户控件
private void OnControlLoaded(object sender, RoutedEventArgs e) { TextBoxXYZ.Focus(); }
我把它设置在PageLoaded()或控件加载,但然后我打电话给WCFasynchronous服务,做的东西,似乎失去了重点。 我必须把它放在所有我做的事情的最后。 这很好,但是有时我会对代码进行更改,然后忘记我也在设置游标。
我不喜欢为UserControl设置另一个选项卡作用域的解决scheme。 在这种情况下,通过键盘导航时,您将有两个不同的插入点:在窗口和另一个 – 在用户控制内。 我的解决scheme是简单地将焦点从用户控制redirect到内部子控件。 设置用户控件可调焦(因为默认为false):
<UserControl ..... Focusable="True">
并在代码隐藏中重写焦点事件处理程序:
protected override void OnGotFocus(RoutedEventArgs e) { base.OnGotFocus(e); MyTextBox.Focus(); } protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) { base.OnGotKeyboardFocus(e); Keyboard.Focus(MyTextBox); }
我在设置键盘焦点到WPF用户控件的canvas上也有同样的问题。 我的解决scheme
- 在XAML中将元素设置为
Focusable="True"
-
在
element_mousemove
事件中创build简单的检查:if(!element.IsKeyBoardFocused) element.Focus();
在我的情况下,它工作正常。