2016-10-09 90 views
1

我已经通过其他几个有关WPF和焦点的帖子,最好的我可以确定我的代码中缺少的东西。我正在使用严格的MVVM开发应用程序,所以我试图避免在视图文件中使用任何代码隐藏(当需要隐藏代码时使用附加行为),但是在这一点上,即使将焦点代码放在代码隐藏文件中,视图背后它不起作用。WPF焦点,不能同时获得逻辑和键盘焦点

我有一个主窗口的应用程序,我试图让一个搜索窗口弹出一个热键。我想只要用户点击热键,键盘焦点就在搜索文本上,所以它只是热键,然后输入搜索词。尽管键盘声称专注于元素,但除了逻辑焦点以外的所有内容都在工作。

我似乎无法从代码中同时获取键盘和逻辑焦点。但是,如果我在搜索框出现后立即点击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) 

我一直在努力,包括一切我能想到的,但我不能让逻辑焦点显示,除了空什么。

回答

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