Управление фокусом WPF в .Net 4.0 - PullRequest
4 голосов
/ 23 августа 2011

У меня есть приложение в WPF, которое должно использоваться исключительно клавиатурой, поэтому мы очень требовательны к поведению фокуса.

Итак, мы получаем PreviewLostKeyboardFocus для текстового поля.При определенных обстоятельствах мы отключаем следующие 5 полей и хотим, чтобы фокус переместился на поле после этого.Можно предположить, что фокус сделает это, найдя следующее фокусируемое поле, это то, что происходит, если я не отключил поля в событии предварительного просмотра.Это не так, он удерживает фокус на первом текстовом поле.

Я пытался навести фокус на Keyboard.Focus(uielement), но ничего не происходит.Кажется, что следующая цель фокуса уже зафиксирована.

Как я могу это сделать, или я "делаю это неправильно"?Я не в состоянии изменить требование, которое определяет это поведение;Я знаю, что это несколько странно.

Спасибо.

Редактировать: вот небольшое приложение, которое показывает это поведение.XAML:

<Window x:Class="WpfApplication4.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"
    FocusManager.FocusedElement="{Binding ElementName=textBox0}"
    >
  <StackPanel>
    <TextBox Height="23" Margin="5" Name="textBox0" Width="120" />
    <TextBox Height="23" Margin="5" Name="textBox1" Width="120" PreviewLostKeyboardFocus="textBox1_PreviewLostKeyboardFocus"/>
    <TextBox Height="23" Margin="5" Name="textBox2" Width="120" />
    <TextBox Height="23" Margin="5" Name="textBox3" Width="120" />
    <TextBox Height="23" Margin="5" Name="textBox4" Width="120" />
  </StackPanel>
</Window>

Кодовый код:

using System.Windows;
using System.Windows.Input;

namespace WpfApplication4 {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }
        private void textBox1_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
            textBox2.IsEnabled = false;
            textBox3.IsEnabled = false;
        }
    }
}

Очевидная вещь, которую нужно попробовать (по крайней мере, для меня), - поместить Keyboard.focus(textBox4); в обработчик событий PreviewLostKeyboardFocus.Это, конечно, не сработало, оно вызывает цикл, который снова запускает событие PreviewLostKeyboardFocus ....

Еще одно редактирование: я обнаружил, что использование точек останова в textBox1_PreviewLostKeyboardFocus() иногда вызывает еговести себя, а иногда даже не отключить 2-й и 3-й текстовые поля.Я думаю о проблеме гонки / многопоточности.

Ответы [ 2 ]

3 голосов
/ 01 сентября 2011

Я не уверен, что именно вызывает такое поведение, но из прошлого опыта система фокусировки WPF крайне ненадежна после какого-либо изменения элементов управления или при ручной настройке фокуса.

Однако при использовании Dispatcher для выполнениясмена фокуса после того, как WPF догнал изменения в элементах управления, часто решает проблему.

Это отлично работает в моем тестировании

private void textBox1_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
    textBox2.IsEnabled = false;
    textBox3.IsEnabled = false;

    this.Dispatcher
        .BeginInvoke(new Action(() => Keyboard.Focus(textBox4)), 
        System.Windows.Threading.DispatcherPriority.Input, null);
}
0 голосов
/ 01 сентября 2011

Вы можете сделать это лучше с помощью модели представления.Ваша модель представления может установить свойства bool для включения / выключения полей.Я уверен, что вы не захотите заливать подобную модель, но это может сделать поведение приложения более предсказуемым. Я думаю, что wpf знает, как пропустить табуляции при отключенных элементах управления, и вы сможете найти желаемое поведение табуляции на вкладке.навигация.

...