0

我正在尝试使用以下结构的应用程序使(键盘)焦点正常工作:

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 中的所有项目中,只有一个 ContentControls 是实际可见的(“当前”一个)。所以,基本上,我让第一件事可见,其中的 OK 按钮有焦点,用户可以按 Enter 确认。然后隐藏这个,显示下一个,并且它的主控件(例如文本框)有焦点,用户可以按回车确认(小事件处理使在文本框中回车确认项目)等等。

一切完成后,用户可以单击工具栏中的按钮重新开始,使第一个 ContentControl 再次可见。但这一次它没有焦点。我不知道谁有重点,我希望它像一开始那样工作。我试图将焦点设置到刚刚显示的 ContentControl (它有效,通过虚线可见),但它不会将焦点设置为它的孩子。由于我不知道选择了哪个数据模板(好吧,不是没有编写特殊代码),我不能只是手动设置焦点或通过绑定到孩子。也许我在这一点上错过了一件简单的事情?

另一方面,当用户手动单击活动的 ContentControl 按钮或文本框时,他可以通过 enter 确认,但 ItemsControl 似乎有焦点,而不是下一个项目。我只是无法理解这个焦点问题。有简单的解决方案吗?我是否必须编写代码来遍历 ContentControl 中的树以获得正确的数据模板?然后,我可以以某种方式关注数据模板或设置为 FocusedElement 的控件,还是必须分别为每个数据模板编写代码?

4

1 回答 1

0

您应该实现一个可以在需要时从 ViewModel 触发到焦点元素的操作。试试这个代码:

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);
            }
        }
    }
}

然后在 WPF 中:

<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
于 2013-02-06T08:02:24.933 回答