Подтвердить что ты не робот

В WPF, при каких обстоятельствах Visual.PointFromScreen выдает InvalidOperationException?

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

public static Point GetMousePosition(this Visual relativeTo)
{
    return relativeTo.PointFromScreen(GetMousePositionOnScreen());
}

Иногда (обычно, когда я только что переключался между двумя элементами управления вкладками) PointFromScreen выводит InvalidOperationException с сообщением Этот Visual не подключен к PresentationSource.

При просмотре свойств, доступных на Visual, я не вижу никакого отношения к PresentationSource.

Учитывая Visual, как я могу определить, будет ли это исключение, когда я вызываю PointFromScreen на нем?

4b9b3361

Ответ 1

Есть статический метод PresentationSource.FromVisual, который:

Возвращает источник, в котором представлен предоставленный Visual.

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

Ответ 2

У меня была аналогичная проблема с визуализацией, сделанной на заказ.

Решение заключалось в том, чтобы отложить проблемную задачу через Dispatcher (отложенное выполнение с приоритетом фона в этом случае)...

public void MyProblematicDisplayMethod(Symbol TargetSymbol)
{
    this.HostingScrollViewer.BringIntoView(TargetSymbol.HeadingContentArea);
    ...
    // This post-call is needed due to WPF tricky rendering precedence (or whatever it is!).
    this.HostingScrollViewer.PostCall(
        (scrollviewer) =>
        {
            // in this case the "scrollviewer" lambda parameter is not needed
            var Location = TargetSymbol.Graphic.PointToScreen(new Point(TargetSymbol.HeadingContentArea.Left, TargetSymbol.HeadingContentArea.Top));
            ShowOnTop(this.EditBox, Location);
            this.EditBox.SelectAll();
        });
     ...
}

/// <summary>
/// Calls, for this Source object thread-dispatcher, the supplied operation with background priority (plus passing the source to the operation).
/// </summary>
public static void PostCall<TSource>(this TSource Source, Action<TSource> Operation) where TSource : DispatcherObject
{
    Source.Dispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(delegate(Object state)
                                        { Operation(Source); return null; }),
        null);
}

Я использовал этот PostCall в других ситуациях рендеринга, связанных с ScrollViewer.

Ответ 3

Я обнаружил, что вы можете протестировать IsVisible перед вызовом PointFromScreen для защиты от InvalidOperationException.

Ответ 4

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

public static Point GetMousePosition(this Visual relativeTo)
{
    if(PresentationSource.FromVisual(relativeTo) != null)
       return relativeTo.PointFromScreen(GetMousePositionOnScreen());
    else
       return new Point();
}

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

Ответ 5

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

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