С# ComboBox GotFocus

У меня есть С# ComboBox с использованием WPF. У меня есть код, который выполняется при активации ComboBox GotFocus. Проблема в том, что событие GotFocus выполняется каждый раз, когда выделение производится из ComboBox. Например, GotFocus выполняется при первом нажатии на ComboBox, а затем, когда вы делаете выделение, даже если вы не нажимаете на какой-либо другой элемент управления.

Возможно ли предотвратить запуск этого события, если в списке сделан выбор или есть флаг или что-то еще в обработчике событий, которое может быть использовано для определения того, был ли обработчик события GotFocus уволен как результат выбора пользователем элемента в списке?

Ответ 1

Вы можете решить эту проблему при следующей проверке:

private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (e.OriginalSource.GetType() == typeof(ComboBoxItem))
        return;
    //Your code here
}

Этот код будет фильтровать все фокусные события из элементов (поскольку они используют событие маршрутизации пузырьков). Но есть еще одна проблема - специфическое поведение фокуса WPF ComboBox: когда вы открываете раскрывающийся список с элементами, которые теряют фокус и элементы, получаемые ComboBox. Когда вы выбираете элемент item item, теряющий фокус, и ComboBox возвращается. Выпадающий список похож на другой элемент управления. Вы можете увидеть это простым кодом:

private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
    {
        Trace.WriteLine("Got " + DateTime.Now);
    }
}

private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
    if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
    {
        Trace.WriteLine("Lost " + DateTime.Now);
    }
}

Итак, вы получите в любом случае два фокусных события: когда вы выбираете ComboBox и когда вы выбираете что-то в нем (фокус вернется в ComboBox).

Чтобы отфильтровать возвращенный фокус после выбора элемента, вы можете попытаться использовать события DropDownOpened/DropDownClosed с некоторым флагом поля.

Итак, последний код с одним событием фокуса:

private bool returnedFocus = false;

private void myComboBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (e.OriginalSource.GetType() != typeof(ComboBoxItem) && !returnedFocus)
    {
        //Your code.
    }
}

private void myComboBox_LostFocus(object sender, RoutedEventArgs e)
{
    if (e.OriginalSource.GetType() != typeof(ComboBoxItem))
    {
        ComboBox cb = (ComboBox)sender;
        returnedFocus = cb.IsDropDownOpen;
    }
}

Выберите из этих примеров то, что вам действительно нужно для вашего приложения.

Ответ 2

Я не слишком горячий в WPF; но если вы пытаетесь обнаружить изменения в списке (нажмите новое значение и т.д.), вы можете использовать события SelectedIndexChanged.

С другой стороны, если вы действительно хотите знать просто, когда элемент управления сосредоточен, вы можете отфильтровать его, сказав что-то вроде:

if (combo1.Focused && combo1.SelectedIndex == -1)
{
     ...
}

..? Это действительно зависит от того, что вы пытаетесь обнаружить, точно.

Ответ 3

Другое решение - определить, является ли новый сфокусированный элемент существующим элементом в поле со списком. Если true, то событие LostFocus не должно выполняться, потому что в поле со списком все еще есть фокус. В противном случае элемент вне поля со списком получал фокус.

В нижеприведенном snipplet кода я добавил функциональность в пользовательский класс combobox

public class MyComboBox : System.Windows.Controls.Combobox
{
    protected override void OnLostFocus(RoutedEventArgs e)
    {
        //Get the new focused element and in case this is not an existing item of the current combobox then perform a lost focus command.
        //Otherwise the drop down items have been opened and is still focused on the current combobox
        var focusedElement = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
        if (!(focusedElement is ComboBoxItem && ItemsControl.ItemsControlFromItemContainer(focusedElement as ComboBoxItem) == this))
        {
            base.OnLostFocus(e);
            /* Your code here... */
        }
    }
}