Wpf Can';t将焦点设置为UserControl的子级
我有一个Wpf Can';t将焦点设置为UserControl的子级,wpf,focus,user-controls,focusmanager,Wpf,Focus,User Controls,Focusmanager,我有一个用户控件,其中包含一个文本框。加载主窗口时,我希望将焦点设置到此文本框,因此我将Focusable=“True”GotFocus=“UC_GotFocus”添加到UserControls定义中,并将FocusManager.FocusedElement=“{Binding ElementName=login}”添加到主窗口定义中。在UC\u GotFocus方法中,我只需对我想要关注的控件调用.Focus(),但这不起作用 我所需要做的就是在应用程序启动时在UserControl接收焦点
用户控件
,其中包含一个文本框
。加载主窗口时,我希望将焦点设置到此文本框,因此我将Focusable=“True”GotFocus=“UC_GotFocus”
添加到UserControl
s定义中,并将FocusManager.FocusedElement=“{Binding ElementName=login}”添加到主窗口定义中。在UC\u GotFocus
方法中,我只需对我想要关注的控件调用.Focus()
,但这不起作用
我所需要做的就是在应用程序启动时在UserControl
接收焦点中设置一个TextBox
感谢您的帮助。WPF支持两种不同的焦点:
键盘焦点
逻辑焦点
FocusedElement
属性获取或设置焦点范围内的逻辑焦点。我怀疑您的文本框
具有逻辑焦点,但其包含的焦点范围不是活动焦点范围。因此,它没有键盘焦点
所以问题是,你的视觉树中有多个焦点范围吗?最近我有一个列表框,其中包含一些文本块。我希望能够双击文本块并将其变成一个文本框,然后集中精力并选择所有文本,这样用户就可以开始键入新名称(类似于Adobe Layers)
不管怎样,我是在一个活动中这样做的,但它就是不起作用。对我来说,这里的魔弹是确保我将事件设置为已处理。我认为这是在设置焦点,但一旦事件沿着这条路径发展,它就在切换逻辑焦点
这个故事的寓意是,确保您将事件标记为已处理,这可能是您的问题。我注意到一个焦点问题,它与在ElementHosts中托管WPF UserControls有关,ElementHosts包含在通过MdiParent属性设置为MDI子级的表单中
我不确定这是否与其他人遇到的问题相同,但您可以通过以下链接深入了解详细信息
我最近修复了登录启动屏幕的问题,该屏幕在首次加载主窗口时通过故事板显示
我相信有两个解决办法。一个是使包含元素成为焦点范围。另一个是处理由加载的窗口触发的故事板的故事板完成事件
这个故事板使用户名和密码画布可见,然后逐渐变为100%不透明。关键是用户名控件在脚本运行之前不可见,因此该控件在可见之前无法获得键盘焦点。让我有一段时间不感兴趣的是它有“焦点”(即焦点是真的,但事实证明这只是逻辑焦点),直到阅读Kent Boogaart的答案并查看微软的WPF,我才知道WPF有逻辑焦点和键盘焦点的概念
一旦我这样做了,我的特定问题的解决方案就很简单:
1) 使包含的元素成为焦点范围
<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
<TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
</TextBox>
</Canvas>
请注意,调用item.Focus()会导致调用Keyboard.Focus(this),因此不需要显式调用它。看到这个问题了吗
将用户控件设置为Focusable=“True”(XAML)
处理控件上的GotFocus事件,并调用yourTextBox.Focus()
处理窗口上加载的事件,并调用控件。Focus()
我有一个示例应用程序在我键入时使用此解决方案运行。如果这对您不起作用,则一定是由于您的应用程序或环境特定的原因导致了问题。在你最初的问题中,我认为是绑定造成了问题。
我希望这能有所帮助。这很愚蠢,但它很有效:
弹出一个等待一段时间的线程,然后返回并设置所需的焦点。它甚至可以在元素宿主的上下文中工作
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();
}));
}
);
}
我发现了一系列关于WPF focus的博客文章
它们都很好阅读,但第三部分专门讨论了如何在UserControl中为UI元素设置焦点。“在应用程序启动时设置初始焦点时,要接收焦点的元素必须连接到PresentationSource,并且该元素必须将Focusable和IsVisible设置为true。建议将初始焦点设置在加载的事件处理程序中”(MSDN)
只需在窗口(或控件)的构造函数中添加一个“已加载”的事件处理程序,并在该事件处理程序中调用目标控件上的Focus()方法
public MyWindow() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
}
void MyWindow_Loaded(object sender, RoutedEventArgs e) {
textBox.Focus();
}
在经历了一场“WPF初始焦点噩梦”之后,根据stack上的一些答案,以下内容证明是最好的解决方案
首先,在启动时添加App.xaml(),如下所示:
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初始焦点由于某些框架竞争条件而大部分失败
我发现下面的解决方案是最好的,因为它在全球范围内用于整个应用程序
希望对你有帮助
Oran我有一个带有两个文本框的用户控件-堆栈面板。这些文本框是在CONSTRUCTOR中添加的,而不是在xaml中添加的。当我尝试聚焦第一个文本框时,什么都没有发生。
加载事件的siggestion修复了我的问题。只需在加载事件和所有事件中调用control.Focus()。假设您要为Username文本框设置焦点,则用户可以在每次显示时直接键入
在控件的构造函数中:
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
在WPF用户控件中将键盘焦点设置为画布时,我也遇到了同样的问题。
我的解决方案
在XAML中,将元素设置为Focusable=“True”
在element\u mousemove
事件中创建简单检查:
if(!element.IsKeyBoardFocused)
element.Focus();
就我而言,它很好用。在尝试了上述建议的组合之后,我能够
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
if(!element.IsKeyBoardFocused)
element.Focus();
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
ControlXYZ.Focus();
}
private void OnControlLoaded(object sender, RoutedEventArgs e)
{
TextBoxXYZ.Focus();
}
casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
{
x.Focus();
}), DispatcherPriority.ApplicationIdle, casted);
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());
<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);
}
<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>
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();
}));
});
}
}
}