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