WPF: фокус в окне и UserControl

Я пытаюсь правильно настроить UserControl и сбит с толку. Логическое дерево выглядит так.

|-Window
  -Grid
    -TabControl
      -TabItem
        -StackPanel
          -MyUserControl
            |-StackPanel
              -GroupBox
                -Grid
                  -ComboBox
                    -Textbox1
                      -Textbox2

Все работает нормально, за исключением случаев, когда преобразователь видимости для ComboBox возвращает Visibility.Collapsed (не позволяет пользователю изменять режим базы данных), а затем, когда выбрано текстовое поле1, вместо возможности перехода через элементы управления в UserControl фокус смещается на кнопка объявлена ​​внизу окна. Ни для чего другого, кроме отображаемых элементов управления, не установлены свойства TabIndex или FocusManager.

Я бьюсь головой о кирпичную стену и, должно быть, что-то упускаю. Я пробовал IsFocusScope = True / False, играл с FocusedElement, и ничего не работает, если этот ComboBox невидим (Visibility.Collapsed).

<Window x:Class="MyNamespace.Client.WinInstaller"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    FocusManager.FocusedElement="{Binding ElementName=tabWizard}">
    <Window.Resources>
        <props:Settings x:Key="settings" />
    </Window.Resources>
    <Grid Grid.IsSharedSizeScope="True">
        <!-- row and column definitions omitted -->

        <loc:SmallHeader Grid.Row="0" x:Name="headerBranding" HeaderText="Setup" />
        <TabControl x:Name="tabWizard" DataContext="{StaticResource settings}" SelectedIndex="0" FocusManager.IsFocusScope="True">
            <TabItem x:Name="tbStart" Height="0">
                <StackPanel>
                    <TextBlock Text="Database Mode"/>
                    <loc:DatabaseSelector x:Name="dbSelector" AllowChangeMode="False" TabIndex="1"
                                          AvailableDatabaseModes="SQLServer" IsPortRequired="False"
                                          DatabaseMode="{Binding Default.DbMode,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                          DatabasePath="{Binding Default.DatabasePath,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                </StackPanel>
            </TabItem>
        ...

Верхняя часть пользовательского элемента управления находится ниже:

<UserControl x:Class="MyNamespace.Client.DatabaseSelector"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="root"
    FocusManager.IsFocusScope="True"
    FocusManager.FocusedElement="{Binding ElementName=cboDbMode}">
    <UserControl.Resources>
        <conv:DatabaseModeIsFileBased x:Key="DatabaseModeIsFileBased"/>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    </UserControl.Resources>
    <StackPanel DataContext="{Binding}">
        <GroupBox>
            <Grid>
                <!-- row and column definitions omitted -->
                <Label Content="Database Mode"/>
                <ComboBox x:Name="cboDbMode" SelectedValue="{Binding ElementName=root,Path=DatabaseMode,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                          DisplayMemberPath="Value" SelectedValuePath="Key" TabIndex="1" Visibility="{Binding AllowChangeMode,ElementName=root,Converter={StaticResource BooleanToVisibilityConverter}}" />
                   <!-- AllowChangeMode is a DependencyProperty on the UserControl -->
                <Grid><!-- row and column definitions omitted -->
                    <Label "Host"/>
                    <TextBox x:Name="txtDBHost" Text="{Binding ElementName=root,Path=DatabaseHost,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TabIndex="2" />
                    <TextBox x:Name="txtDBPort" Text="{Binding ElementName=root,Path=DatabasePortString,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TabIndex="3" />

person Echilon    schedule 04.03.2010    source источник


Ответы (2)


Я знаю, что ответ пришел довольно поздно ... но пробовали ли вы:

<UserControl ... KeyboardNavigation.TabNavigation="Local">

Это гарантирует, что после того, как ваш UserControl получит фокус, вы будете перемещаться только через TabStop в своем UserControl (вместо того, чтобы беспокоиться о конфликтующих значениях TabIndex в вашем приложении). После прохождения TabStops вашего UserControl, TabNavigation вернется к TabStop за его пределами.

http://msdn.microsoft.com/en-us/library/system.windows.input.keyboardnavigationmode.aspx

person Scott    schedule 13.05.2011

Возможно, проблема в том, что вы скрываете FocusManager.FocusedElement. В любом случае, вы могли бы облегчить жизнь, просто устранив некоторые усложняющие факторы:

  1. Удалите FocusManager.FocusedElement ... ComboBox в любом случае является первым элементом управления.
  2. Удалите FocusManager.IsFocusScope ... Я полагаю, что это нормально, если каждый раз, когда вы вводите пользовательский элемент управления, будет фокусироваться первый элемент управления внутри, а не тот, который был сфокусирован, когда вы его оставили. Просто позвольте пользовательскому элементу управления быть «встроенным» в окружающие элементы управления.
  3. Удалите явные TabIndices в UserControl. Ваш макет уже подразумевает такой же порядок.

Если вы устраните эти три усложняющих фактора, возможно, вы уже сделали. Возможно, вам также нужно установить UserControl Focusable = False, s.t. фокус передается первому фокусируемому элементу управления внутри - comboBox или TextBox1.

person Simon D.    schedule 26.03.2010