【问题标题】:WPF Focus, can't get both logical and keyboard focusWPF Focus,无法同时获得逻辑和键盘焦点
【发布时间】:2016-10-09 18:02:19
【问题描述】:

我已经阅读了其他几篇关于 WPF 和焦点的帖子,我能想到的最好的结果是我的代码中缺少一些东西。我正在使用严格的 MVVM 开发应用程序,因此我试图避免视图文件中的任何代码隐藏(在需要代码隐藏时使用附加行为),但此时甚至将焦点代码放在代码中 -在视图后面它不起作用。

我有一个带有主窗口的应用程序,我试图在热键上弹出一个搜索窗口。我希望用户一按热键,键盘焦点就在搜索文本上,所以它只是热键,然后输入您的搜索词。此时,除了逻辑焦点之外的所有内容都在起作用,即使键盘声称已将焦点放在元素上。

我似乎无法让它同时从代码中获取键盘和逻辑焦点。但是,如果我一出现搜索框就点击 Tab,我会直接进入文本框。

主窗口代码:

<ribbon:RibbonWindow x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
    xmlns:attached="clr-namespace:UserInterface.Attached"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF45"
    xmlns:viewModels="clr-namespace:UserInterface.ViewModels"
    xmlns:views="clr-namespace:UserInterface.Views"
    xmlns:layout="clr-namespace:UserInterface.ViewModels.Layout"
    xmlns:layout1="clr-namespace:UserInterface.Views.Layout"
    MinHeight="560"
    MinWidth="950"
    WindowStartupLocation="CenterScreen" 
    Icon="{Binding Layout.IconPath}"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    FocusManager.FocusedElement="{Binding ElementName=LayoutControl}"
    Title="{Binding Layout.Title}">

<!-- Ribbon menu shortcuts  -->
<Window.InputBindings>
    <KeyBinding Modifiers="Control" Key="T" Command="{Binding Layout.Commands[GlobalObjectSearch]}" />
</Window.InputBindings>

<Grid>
    <ContentPresenter Content="{Binding Layout}" x:Name="LayoutControl">
        <ContentPresenter.Resources>
            <DataTemplate DataType="{x:Type layout:MainViewModel}">
                <layout1:MainView/>
            </DataTemplate>
        </ContentPresenter.Resources>
    </ContentPresenter>
</Grid>
</ribbon:RibbonWindow>

使搜索窗口出现的代码:

    public SelfClosingDialogView ShowSelfClosingDialog(IWindowDialogViewModel dataContext)
    {
        dataContext.CheckWhetherArgumentIsNull(nameof(dataContext));

        var view = new SelfClosingDialogView
        {
            DataContext = dataContext,
            Owner = Application.Current?.MainWindow
        };

        view.Show();

        return view;
    }

搜索窗口代码(重复使用,非常通用):

<Window x:Class="UserInterface.Views.DialogViews.SelfClosingDialogView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:attached="clr-namespace:UserInterface.Attached"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    mc:Ignorable="d"
    SizeToContent="WidthAndHeight"
    WindowStyle="None"
    WindowStartupLocation="CenterOwner">

<!-- Allow view models to cause the window to close -->
<Window.Style>
    <Style TargetType="{x:Type Window}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsClosed}" Value="true">
                <!-- Executes close -->
                <Setter Property="attached:WindowCloseBehavior.Close" Value="true" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Style>

<!-- Displays the passed-in view model -->
<Grid>
    <ContentPresenter x:Name="DialogPresenter" Content="{Binding}" Margin="0" />
</Grid>
</Window>

我的搜索视图代码:

<UserControl x:Class="UserInterface.Views.DialogViews.ObjectSearchView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:dialogViewModels="clr-namespace:UserInterface.ViewModels.DialogViewModels"
         xmlns:utils="clr-namespace:WPF.Utils"
         xmlns:attached="clr-namespace:UserInterface.Attached"
         mc:Ignorable="d"
         d:DataContext="{d:DesignInstance dialogViewModels:ObjectSearchViewModel}"
         MinWidth="250"
         Focusable="True"
         FocusManager.IsFocusScope="True">
<UserControl.InputBindings>
    <KeyBinding Key="Enter" Command="{Binding BrowseToObjectCommand}" />
    <KeyBinding Key="Escape" Command="{Binding CloseWindowCommand}" />
</UserControl.InputBindings>
<UserControl.Resources>
    <Style BasedOn="{StaticResource FormTextBlockStyle}" TargetType="TextBlock" />
</UserControl.Resources>

<StackPanel>
    <TextBox Name="SearchText" 
             Focusable="True"
             Text="{utils:ValidatingLiveBinding SearchText}" 
             attached:NavigatingListBoxBehavior.LinkedListBox="{Binding ElementName=SearchResults}">
    </TextBox>
    <ScrollViewer HorizontalScrollBarVisibility="Hidden"
                  VerticalScrollBarVisibility="Auto"
                  MaxHeight="400">
        <ListBox Name="SearchResults"
                 ItemsSource="{Binding SearchResults}" 
                 SelectedItem="{Binding SelectedSearchItem}" 
                 Visibility="{Binding HasSearchResults, Converter={StaticResource BooleanToVisibilityConverter}}"
                 attached:ItemsControlProperties.DoubleClickCommand="{Binding BrowseToObjectCommand}"
                 KeyboardNavigation.IsTabStop="False"
                 IsSynchronizedWithCurrentItem="True" />
    </ScrollViewer>
</StackPanel>
</UserControl>

最后,我试图获得焦点的代码隐藏技巧(加上调试代码,这样我就不会失去焦点来回切换到 Visual Studio):

public partial class ObjectSearchView : UserControl
{
    public ObjectSearchView()
    {
        InitializeComponent();
        this.Loaded += this.OnLoad;
    }

    private void OnLoad(object sender, RoutedEventArgs e)
    {
        this.PrintFocusInfo();
        FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), this.SearchText);
        this.PrintFocusInfo();
        this.SearchText.Focus();
        this.PrintFocusInfo();
        Keyboard.Focus(this.SearchText);
        this.PrintFocusInfo();
    }

    [Conditional("DEBUG")]
    private void PrintFocusInfo()
    {
        var logicalElement = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this.SearchText));
        Debug.WriteLine("Current logical focus is on '{0}', of type '{1}' ({2})".FormatInvariantCulture((logicalElement as FrameworkElement)?.Name, logicalElement?.GetType().Name, logicalElement));
        var focusedElement = Keyboard.FocusedElement;
        Debug.WriteLine(
            "Current Keyboard Focus is on '{0}', of type '{1}' ({2})".FormatInvariantCulture(
                (focusedElement as FrameworkElement)?.Name,
                focusedElement.GetType().Name,
                focusedElement));
    }
}

输出窗口内容:

Current logical focus is on '', of type '' ()
Current Keyboard Focus is on '', of type 'MainWindow' (UserInterface.Views.MainWindow)
Current logical focus is on '', of type '' ()
Current Keyboard Focus is on '', of type 'MainWindow' (UserInterface.Views.MainWindow)
Current logical focus is on '', of type '' ()
Current Keyboard Focus is on 'SearchText', of type 'TextBox' (System.Windows.Controls.TextBox)
Current logical focus is on '', of type '' ()
Current Keyboard Focus is on 'SearchText', of type 'TextBox' (System.Windows.Controls.TextBox)

我已尝试包含我能想到的所有内容,但除了 null 之外,我无法获得逻辑焦点来显示任何内容。

【问题讨论】:

    标签: wpf mvvm focus


    【解决方案1】:

    这是我最终创建的行为,它为我解决了这个问题。还有很多我不知道为什么会这样......但如果你在让 Focus 合作时遇到问题,看起来关键是在 IsVisible 设置为 true 并让 Dispatcher 设置焦点时抓住它为你。我将此事件链接到文本框上的 IsVisibleChanged 元素(通过附加行为)。

        private void SetFocusOnVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                this.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() => this.AssociatedObject.Focus()));
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-23
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 2015-03-29
      • 2016-05-20
      相关资源
      最近更新 更多