如何停止FocusManager在使用IsFocusScope选项时将焦点移动到打开的Popup外部

Nov*_*i S 3 wpf

我有两个控件a ToolBar和a TextBox.ToolBar有一个Button打开Popup另一个的工具栏Button.

当前行为:如果我在里面单击TextBox并且它变得聚焦,然后单击按钮从中ToolBar打开弹出窗口TextBox仍然聚焦并接收所有键盘输入.

现在我知道这是FocusScope中的项目的默认行为ToolBar,但是当弹出窗口打开时我不需要这种行为.我怎么能避免呢?

这是一个例子:

<Window x:Class="WpfApplication67.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
</Window.Resources>
<StackPanel HorizontalAlignment="Left" Width="400">
    <ToolBar>
        <ToggleButton Name="openButton">Open Popup</ToggleButton>
        <Popup Focusable="True"
            Placement="Right"        
            StaysOpen="False" 
            IsOpen="{Binding IsChecked, ElementName=openButton, Mode=TwoWay}"
            PlacementTarget="{Binding ElementName=openButton}">
            <StackPanel 
                Width="100" 
                Height="100" 
                Background="DarkGray" 
                Focusable="True">
                    <Button>More</Button>
                </StackPanel>
        </Popup>
    </ToolBar>

    <TextBox Text="Set focus on this..." />

</StackPanel>
Run Code Online (Sandbox Code Playgroud)

编辑:我正在努力寻找一个解释,关于谁将焦点移动到嵌套的FocusScope内的按钮点击,以及如何阻止一些按钮(如Popup中的那个)进行操作.

Roh*_*ats 5

你主要有三个要求(如果错了,请纠正我):

  1. 如果弹出窗口,焦点应该在popUp内部,即在StackPanel上.
  2. 在popUp关闭时,焦点应该保留回textBox.
  3. 单击popUp中的按钮时,焦点不应该离开popUp.

让我们逐一挑选这些要求.

如果弹出窗口,焦点应该在popUp内部,即在StackPanel上.

就像我在评论中提到的那样,将重点放在Opened了PopUp事件的stackPanel上:

private void Popup_Opened(object sender, EventArgs e)
{
   stackPanel.Focus();
}
Run Code Online (Sandbox Code Playgroud)

在popUp关闭时,焦点应该保留回textBox.

挂钩关闭事件并将焦点放回TextBox:

private void Popup_Closed(object sender, EventArgs e)
{
   textBox.Focus();
}
Run Code Online (Sandbox Code Playgroud)

单击popUp中的按钮时,焦点不应该离开popUp.

现在,是棘手的部分.正如您在popUp中单击按钮时在评论中所提到的,焦点移动到PopUp之外.

你可以做的阻止是将处理程序附加到PreviewLostKeyboardFocusstackPanel的事件.如果keyBoard焦点位于popUp中,则e.Handled = true在处理程序中检查条件,设置为在此处处理事件并且不会引发气泡事件,这将强制键盘焦点位于stackPanel之外.

如果你在stackPanel besies按钮内有另一个TextBox,那么处理事件也不允许你在popUp中移动焦点.为了避免这种情况,您可以检查新的焦点元素是否不属于stackPanel,然后只处理该事件.

这是实现它的代码(在StackPanel的PreviewLostKeyboardFocus事件上添加处理程序):

private void stackPanel_PreviewLostKeyboardFocus(object sender, 
                                             KeyboardFocusChangedEventArgs e)
{
   var newFocusedChild = e.NewFocus as FrameworkElement;
   bool isMovingWithinPanel = newFocusedChild != null
                              && newFocusedChild.Parent == stackPanel;

   // If keyboard focus is within stackPanel and new focused element is
   // outside of stackPanel boundaries then only handle the event.
   if (stackPanel.IsKeyboardFocusWithin && !isMovingWithinPanel)
      e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)