WPF - Как Combobox знает, когда закрывать выпадающее меню - PullRequest
3 голосов
/ 15 сентября 2009

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

Ответы [ 2 ]

2 голосов
/ 27 февраля 2013

У меня был такой же вопрос много лет назад с ранней версией Silverlight. Я изучил шаблон элемента управления и декомпилировал код Microsoft, чтобы обнаружить, что для обнаружения кликов они использовали невидимое наложение по всему окну. ComboBox WPF, похоже, не работает так же, но вы можете следовать шаблону Silverlight.

Вы захотите создать прямоугольник того же размера, что и ваше окно. Я делаю это с помощью RowSpan, чтобы покрыть основную сетку, которая содержит все мое приложение. Вы также можете привязать высоту / ширину к высоте / ширине окна. Есть дюжина способов сделать это, просто заполняйте все окно. Придайте прямоугольнику цвет заливки Белый и непрозрачность 0. Для работы нужен цвет заливки, однако при непрозрачности = 0 пользователь его не увидит. В целях отладки вы можете присвоить ему красный цвет и непрозрачность .25.

<Rectangle x:Name="fullScreenOverlay" Grid.RowSpan="3" Opacity="0" Fill="White" Visibility="Collapsed" MouseDown="FullScreenOverlay_OnMouseDown" />

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

Когда вы открываете свой элемент управления, похожий на ComboBox, установите для этого прямоугольника значение Visible, чтобы он мог обнаруживать щелчки / MouseDown.

private void NotificationButton_Click(object sender, RoutedEventArgs e)
{
    fullScreenOverlay.Visibility = Visibility.Visible;
    notificationPopup.Visibility = Visibility.Visible;
}

Когда вы обнаружите щелчок, установите «Прямоугольник» обратно, чтобы он свернулся, и закройте всплывающее окно, как ComboBox. Все сделано.

private void FullScreenOverlay_OnMouseDown(object sender, MouseButtonEventArgs e)
{
    fullScreenOverlay.Visibility = Visibility.Collapsed;
    notificationPopup.Visibility = Visibility.Collapsed;
}

Это не будет определять клики, которые происходят за пределами вашего приложения, как это делает Microsoft ComboBox. Он будет обнаруживать только клики внутри приложения. Но, честно говоря, я так или иначе предпочитаю это.

2 голосов
/ 15 сентября 2009

Вы можете определить свой собственный пользовательский элемент управления и шаблон управления с помощью текстового поля и всплывающего окна. Затем переопределите метод OnApplyTemplate вашего элемента управления и найдите всплывающее окно, используя:

var popup = this.GetTemplateChild("PART_Popup") as Popup;

Теперь вы можете решить, когда отображать или скрывать всплывающее окно, задав для его свойств IsOpen значение true или false.

Чтобы узнать, нажимает ли пользователь на какую-то другую часть вашего пользовательского интерфейса, просто подпишитесь на событие PreviewMouseDown на родительском элементе вашего элемента управления (где-то в коде инициализации вашего элемента управления):

var parent = VisualTreeHelper.GetParent(this) as UIElement;
if(parent != null) {
    parent.PreviewMouseDown += MouseDownHandler;
}

Теперь вы должны получать уведомления всякий раз, когда пользователь щелкает в любом месте контейнера вашего элемента управления. Вы также можете использовать VisualTreeHelper.GetParent (...) рекурсивно, чтобы добраться до корневого элемента (например, окна), пока он не вернет ноль.

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

...