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

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

Проблема возникает из-за того, что на панелях инструментов и в других областях приложения есть несколько кнопок, для которых свойство Focusable имеет значение False. Таким образом, когда они нажимаются, соответствующие действия срабатывают, но наш элемент управления еще не зафиксировал свои изменения, что вызывает проблемы.

Поскольку наш пользовательский интерфейс является модульным/динамическим по своей природе, и поскольку это просто хорошая практика кодирования, эти области не знают друг о друге, поэтому мы не можем просто добавить код в обработчики кнопок, чтобы наш элемент управления зафиксировался. Наш элемент управления должен вместо этого понимать, что было нажато что-то вне его.

Наша первоначальная попытка состояла в том, чтобы использовать обработчик событий уровня класса в GotFocus нашего элемента управления, например...

EventManager.RegisterClassHandler(
    typeof(FrameworkElement),
    PreviewMouseDownEvent,
    new RoutedEventHandler(MyControl_PreviewMouseDownHandler));

private void MyControl_PreviewMouseDown(object sender, RoutedEventArgs e)
{
    // Exit if the sender isn't the original source.
    // This is because we want the deepest-clicked item, but also only want to process this once
    if(sender != e.OriginalSource)
        return;

    var frameworkElement = (FrameworkElement)sender;

    // If the clicked item is a descendant of ThisControl, do nothing.
    if(frameworkElement.IsDescendantOf(NameOfMyControlInstance))
        return;

    CommitChanges();

    // Unsubscribe class handler here
    ??? Can't do!
}

Если бы наш элемент управления потерял фокус, мы бы просто зафиксировали наши изменения и отменили подписку. Кроме того, если обработчик запущен, но OriginalSource находится вне нашего контроля, мы также зафиксируем наши изменения и отменим подписку обработчика. Проблема в том, что вы не можете отменить подписку на обработчики классов! Почему бы и нет, я понятия не имею.

Итак, как мы можем сказать, что пользователь щелкнул вне нашего контроля на что-то, что не перехватит фокус?


person Mark A. Donohoe    schedule 25.01.2016    source источник
comment
Я задал аналогичный вопрос (хотя специально для обновления привязок), мне предложили использовать привязку PropertyChanged с Delay (.NET 4.5 и выше). Не знаю, может ли это соответствовать вашему сценарию: конкретный вопрос   -  person Jcl    schedule 25.01.2016
comment
Да, обычно я бы так поступил. Однако проблема заключается в том, что это сетка данных, в которой и строка, и ячейка могут находиться в режиме «Редактировать». Если пользователь ввел недопустимое значение (почему мы не можем сделать это в «Изменено», иначе у них было бы много недопустимых значений), нам нужно знать, есть ли ошибка в каких-либо привязках, и отменить их, если вы отойдете от табуляции. . Немного запутался, как обойти это. Если бы мы только могли отменить регистрацию чертовых обработчиков. Конечно, я мог бы добавить код, чтобы обойти их, но в FrameworkElement это МНОГО мертвых вызовов.   -  person Mark A. Donohoe    schedule 25.01.2016
comment
Другая проблема заключается в том, что если вы нажимаете на другую строку, когда текущая строка имеет ошибку и, следовательно, все еще находится в режиме «Редактировать», а у вас также включена сортировка, возникает исключение, которое вы не можете сортировать при редактировании. Я начинаю понимать, что мне просто нужно отменить любые изменения неверных данных. Это воняет, потому что тогда я не могу использовать шаблоны ошибок и должен полагаться на окна сообщений.   -  person Mark A. Donohoe    schedule 25.01.2016
comment
Я чувствую твою боль, и мне жаль, что я не могу помочь дальше. Некоторое время назад я отказался от WPF... мне все кажется полусырым. Однако мертвые вызовы в основном являются девизом WPF (когда-либо проверяли трассировку стека любого события?), Так что еще один не должен иметь большого значения :-) (шучу)   -  person Jcl    schedule 25.01.2016