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

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

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

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

Вы можете использовать эту небольшую вспомогательную функцию, которую я только что написал, чтобы проверить, является ли элемент видимым для пользователя в данном контейнере. Функция возвращает 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 
  • Как получить центр большого пальца изображения UISlider
  • Как настроить ListField в BlackBerry?
  • Простая всплывающая форма java с по меньшей мере двумя полями
  • Измените сторону, которую текст появится на переключателе
  • Как реализовать перетаскиваемую вкладку с помощью Java Swing?
  • Как программно перемещать UIScrollView для фокусировки в контроле над клавиатурой?
  • ProgressBar в Javafx не обновляется в блоке onAction
  • JTable Right Align Header
  • Что такое MVP и MVC и в чем разница?
  • Обновление пользовательского интерфейса Android с помощью streamов
  • Как сделать фотокамеру доступным?
  • Interesting Posts

    Как не сериализовать свойство __type на объектах JSON

    psql: FATAL: Идентификационная идентификация не удалась для пользователя «postgres»

    Как создать и использовать Google TensorFlow C ++ api

    Может ли мой домовладелец получить доступ к моей личной сети, потому что он контролирует восходящее соединение?

    Ключевое слово не поддерживается: ‘server’

    Как закрыть все фоновые процессы в unix?

    Почему нельзя добавлять / удалять элементы из ArrayAdapter?

    Как добавить каталог в путь к classам в профиле запуска приложения в IntelliJ IDEA?

    Как остановить анимацию (cancel () не работает)

    «Ошибка NoClassDefFoundError: Не удалось инициализировать class»

    Как мне ZIP-файл на C #, без использования сторонних API-интерфейсов?

    Maven – как включить пустые каталоги

    Фиксация сломанной «цепи доверия» в сертификатах Windows 7?

    изменить цвет фона Предпочтения

    Должен ли я использовать атомный для переменной «exit» bool?

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