В WPF, как я могу определить, является ли элемент управления видимым для пользователя?

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

Можно ли каким-либо образом определить, является ли элемент управления видимым для пользователя?

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

4 Solutions collect form web for “В WPF, как я могу определить, является ли элемент управления видимым для пользователя?”

Вы можете использовать эту небольшую вспомогательную функцию, которую я только что написал, чтобы проверить, является ли элемент видимым для пользователя в данном контейнере. Функция возвращает true если элемент частично виден. Если вы хотите проверить, полностью ли он виден, замените последнюю строку на rect.Contains(bounds) .

 private bool IsUserVisible(FrameworkElement element, FrameworkElement container) { if (!element.IsVisible) return false; Rect bounds = element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight)); Rect rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight); return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight); } 

В вашем случае element будет вашим пользовательским element управления и container вашего windows.

 public static bool IsUserVisible(this UIElement element) { if (!element.IsVisible) return false; var container = VisualTreeHelper.GetParent(element) as FrameworkElement; if (container == null) throw new ArgumentNullException("container"); Rect bounds = element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.RenderSize.Width, element.RenderSize.Height)); Rect rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight); return rect.IntersectsWith(bounds); } 

Используйте эти свойства для содержащего элемента управления:

 VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" 

а затем подключить прослушивание к вашим подписчикам INotifyPropertyChanged.PropertyChanged ваших данных.

  public event PropertyChangedEventHandler PropertyChanged { add { Console.WriteLine( "WPF is listening my property changes so I must be visible"); } remove { Console.WriteLine("WPF unsubscribed so I must be out of sight"); } } 

Более подробную информацию см. По адресу : http://joew.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&_c=BlogPart&partqs=cat%3DWPF.

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

Чтобы определить, является ли элемент управления aa видимым для пользователя, вы иногда должны быть в состоянии определить, является ли WPF UIElement кликабельным (или мыши, доступным на ПК) пользователем

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

Поэтому мне пришлось придумать свое решение.

EDIT – у моего оригинального сообщения было другое решение, которое использовало метод InputHitTest. Однако во многих случаях это не сработало, и мне пришлось перепроектировать его. Это решение является гораздо более надежным и, кажется, работает очень хорошо, без ложных негативов или положительных результатов.

Решение:

  1. Получить абсолютное положение объекта относительно главного windows приложения
  2. Вызовите VisualTreeHelper.HitTest на всех его углах (вверху слева, внизу слева, вверху справа, внизу справа)
  3. Мы вызываем объект Fully Clickable, если объект, полученный из VisualTreeHelper.HitTest равен исходному объекту или визуальному родительскому VisualTreeHelper.HitTest для всех его углов и частично кликирован для одного или нескольких углов.

Обратите внимание: # 1: определение здесь полностью кликабельного или частично кликабельного не является точным – мы просто проверяем, что все четыре угла объекта доступны для клика. Если, например, кнопка имеет 4 кликабельных угла, но в центре есть пятно, которое не является кликабельным, мы все равно будем считать его полностью доступным. Проверить все точки в заданном объекте было бы слишком расточительным.

Обратите внимание: # 2: иногда требуется установить для свойства IsHitTestVisible объекта значение true (однако это значение по умолчанию для многих общих элементов управления), если мы хотим, чтобы VisualTreeHelper.HitTest нашел его

  private bool isElementClickable(UIElement container, UIElement element, out bool isPartiallyClickable) { isPartiallyClickable = false; Rect pos = GetAbsolutePlacement((FrameworkElement)container, (FrameworkElement)element); bool isTopLeftClickable = GetIsPointClickable(container, element, new Point(pos.TopLeft.X + 1,pos.TopLeft.Y+1)); bool isBottomLeftClickable = GetIsPointClickable(container, element, new Point(pos.BottomLeft.X + 1, pos.BottomLeft.Y - 1)); bool isTopRightClickable = GetIsPointClickable(container, element, new Point(pos.TopRight.X - 1, pos.TopRight.Y + 1)); bool isBottomRightClickable = GetIsPointClickable(container, element, new Point(pos.BottomRight.X - 1, pos.BottomRight.Y - 1)); if (isTopLeftClickable || isBottomLeftClickable || isTopRightClickable || isBottomRightClickable) { isPartiallyClickable = true; } return isTopLeftClickable && isBottomLeftClickable && isTopRightClickable && isBottomRightClickable; // return if element is fully clickable } private bool GetIsPointClickable(UIElement container, UIElement element, Point p) { DependencyObject hitTestResult = HitTest< T>(p, container); if (null != hitTestResult) { return isElementChildOfElement(element, hitTestResult); } return false; } private DependencyObject HitTest(Point p, UIElement container) { PointHitTestParameters parameter = new PointHitTestParameters(p); DependencyObject hitTestResult = null; HitTestResultCallback resultCallback = (result) => { UIElement elemCandidateResult = result.VisualHit as UIElement; // result can be collapsed! Even though documentation indicates otherwise if (null != elemCandidateResult && elemCandidateResult.Visibility == Visibility.Visible) { hitTestResult = result.VisualHit; return HitTestResultBehavior.Stop; } return HitTestResultBehavior.Continue; }; HitTestFilterCallback filterCallBack = (potentialHitTestTarget) => { if (potentialHitTestTarget is T) { hitTestResult = potentialHitTestTarget; return HitTestFilterBehavior.Stop; } return HitTestFilterBehavior.Continue; }; VisualTreeHelper.HitTest(container, filterCallBack, resultCallback, parameter); return hitTestResult; } private bool isElementChildOfElement(DependencyObject child, DependencyObject parent) { if (child.GetHashCode() == parent.GetHashCode()) return true; IEnumerable elemList = FindVisualChildren((DependencyObject)parent); foreach (DependencyObject obj in elemList) { if (obj.GetHashCode() == child.GetHashCode()) return true; } return false; } private IEnumerable FindVisualChildren(DependencyObject depObj) where T : DependencyObject { if (depObj != null) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { DependencyObject child = VisualTreeHelper.GetChild(depObj, i); if (child != null && child is T) { yield return (T)child; } foreach (T childOfChild in FindVisualChildren(child)) { yield return childOfChild; } } } } private Rect GetAbsolutePlacement(FrameworkElement container, FrameworkElement element, bool relativeToScreen = false) { var absolutePos = element.PointToScreen(new System.Windows.Point(0, 0)); if (relativeToScreen) { return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight); } var posMW = container.PointToScreen(new System.Windows.Point(0, 0)); absolutePos = new System.Windows.Point(absolutePos.X - posMW.X, absolutePos.Y - posMW.Y); return new Rect(absolutePos.X, absolutePos.Y, element.ActualWidth, element.ActualHeight); } 

Тогда все, что необходимо, чтобы выяснить, является ли кнопка (например) кликабельной, является вызов:

  if (isElementClickable 
  • Почему большинство пользовательских интерфейсов однопоточных?
  • Внедрение средства просмотра журналов с помощью WPF
  • Android RecyclerView добавление и удаление элементов
  • Как создать приложение C ++ / CLI Winforms в VS2012?
  • Как отобразить текущее значение предпочтения Android в сводке предпочтений?
  • Переопределить цвета контекстного меню в Android
  • SwingWorker, Thread.sleep () или javax.swing.timer? Мне нужно «вставить паузу»,
  • Пользовательская строка заголовка без дополнения (Android)
  • Выбор нескольких строк в JTable
  • Разница между validate (), revalidate () и invalidate () в графическом интерфейсе Swing
  • Как обновить текстовое поле в графическом интерфейсе из другого streamа
  • Interesting Posts

    Запись на указатель вне границ после malloc (), не вызывающая ошибки

    Как предотвратить закрытие windows браузера?

    Большие целые числа в C #

    Как реализовать возможность для пользователя размещать данные в формате html в безопасном режиме?

    Как использовать arraylist в качестве подготовленного параметра инструкции

    Почему я не могу ping имя компьютера без точки?

    Как создать пользователя SSH, у которого есть разрешение на доступ к определенным папкам в Ubuntu?

    Проблема с Microsoft Office 2016 с Windows 10

    std :: shared_ptr инициализация: make_shared () vs shared_ptr (новый Foo)

    Как HashSet сравнивает элементы для равенства?

    Темабезопасный одноэлементный class

    В чем опасность ручной настройки IncreaseUserVA?

    Где я могу найти журналы при недавней вставке USB в средство просмотра событий?

    Как найти k-й наибольший элемент в несортированном массиве длины n в O (n)?

    Каков наилучший подход для использования Enum в качестве одноэлементной на Java?

    Давайте будем гением компьютера.