Wpf 关注FocusManager、ContentControl和DataTemplate
我试图通过以下结构的应用程序使(键盘)焦点正常工作:Wpf 关注FocusManager、ContentControl和DataTemplate,wpf,focus,datatemplate,focusmanager,Wpf,Focus,Datatemplate,Focusmanager,我试图通过以下结构的应用程序使(键盘)焦点正常工作: ItemsControl DataTemplate for Item ContentControl DataTemplate for Content (multiple, depending on type) Some container Different controls (mainly textbox or OK button should have focus) 在每个内容
ItemsControl
DataTemplate for Item
ContentControl
DataTemplate for Content (multiple, depending on type)
Some container
Different controls (mainly textbox or OK button should have focus)
在每个内容模板的根(“某个容器”)上,我将FocusManager.FocusedElement
设置为模板中的一个控件。在ItemsControl中的所有项中,只有一个ContentControl实际可见(“当前”项)。所以,基本上,我让第一件事是可见的,它的OK按钮有焦点,用户可以按Enter确认。然后这个隐藏,下一个显示,其主控件(例如文本框)有焦点,用户可以按enter键确认(小事件处理使文本框中的enter键确认项目)等等
完成所有操作后,用户可以单击工具栏中的按钮重新开始,使第一个ContentControl再次可见。但这次它没有焦点。我不知道谁有焦点,我希望它能像一开始那样工作。我试图将焦点设置为刚刚显示的ContentControl(它可以工作,通过虚线可见),但它不会将焦点设置为它的子项。由于我不知道选择了哪种数据模板(当然,如果不编写特殊代码的话),我不能只是手动或通过绑定到子级来设置焦点。也许我错过了一件简单的事情
另一方面,当用户手动单击活动的ContentControl按钮或文本框时,他可以用enter确认,但是ItemsControl似乎有焦点,而不是下一个项目。我就是不能集中注意力。有简单的解决办法吗?我是否必须编写代码从ContentControl遍历树以获得正确的datatemplate?然后,我可以只关注设置为FocusedElement的datatemplate或控件,还是必须分别为每个datatemplate编写代码 您应该实现一个动作,该动作可以在需要时从ViewModel触发到focus元素。请尝试以下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interactivity;
using System.Windows;
namespace Behaviors
{
/// <summary>
/// Action to focus target element, if invoked when target is not yet specified, will focus once the target is set
/// </summary>
public class FocusAction : TargetedTriggerAction<DependencyObject>
{
protected override void OnAttached()
{
base.OnAttached();
}
protected override void OnDetaching()
{
base.OnDetaching();
}
protected override void Invoke(object parameter)
{
if (Target is UIElement)
{
if(!((UIElement)Target).IsKeyboardFocusWithin)
((UIElement)Target).Focus();
}
else
invokeOnConnect = true;
}
private bool invokeOnConnect = false;
protected override void OnTargetChanged(DependencyObject oldTarget, DependencyObject newTarget)
{
base.OnTargetChanged(oldTarget, newTarget);
if (invokeOnConnect)
{
invokeOnConnect = false;
Invoke(null);
}
}
}
}
我会尝试,但我不确定这是否解决了问题。我可以触发更改的时间点与现在相同(当其中一个ContentControl可见时,我尝试聚焦正确的控件,但失败并将焦点设置为前一个ContentControl的控件)。。。
<DockPanel>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<nuib:FocusAction TargetName="title"/>
</i:EventTrigger>
<TextBlock x:Name="title"/>
</DockPanel>
xmlns:nuib="clr-namespace:Behaviors;assembly=Nui" // for Action class
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" // .net library for interactivity