2010-01-28 13 views
12

Supponiamo che volevo fare questo, così posso trovare la posizione corrente del mouse rispetto ad una Visual, senza bisogno di accedere a uno specifico evento del mouse:In WPF, in quali circostanze Visual.PointFromScreen genera InvalidOperationException?

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

volte (di solito quando ho appena passato tra due controlli struttura a schede) PointFromScreen genera InvalidOperationException con il messaggio Questo visivo non è collegato ad un PresentationSource.

Osservando le proprietà disponibili su Visual non riesco a visualizzare nessuna informazione relativa a PresentationSource.

Dato un Visual, come posso sapere se sta generando quell'eccezione quando chiamo PointFromScreen su di esso?

risposta

19

C'è un metodo statico PresentationSource.FromVisual cui:

Restituisce la fonte in cui un fornito visiva è presentato.

So che questo non risolve il problema sottostante, ma è possibile verificare che il Visual sia connesso a un PresentationSource prima di chiamare PointFromScreen. Eviterebbe l'eccezione, ma avresti bisogno di fare ulteriori indagini sul motivo per cui non era collegato in primo luogo.

+0

Vero - Sto utilizzando un timer. Occasionalmente il timer scatta quando il Visual non è in buono stato. Posso tranquillamente ignorare il timer se ciò si verifica. Ci proveremo. –

3

Ho avuto un problema simile con un custom-made visivo.

La soluzione era quella di rinviare il compito problematico tramite Dispatcher (esecuzione differita con la priorità di fondo in questo caso) ...

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); 
} 

Ho usato che PostCall in altre situazioni di rendering ScrollViewer correlati.

+0

Oh sì, devo farlo così tanto in WPF che ho un metodo di supporto simile - forse tutti lo fanno ... –

1

in ritardo alla partita di baseball, ma queste risposte mi ha aiutato. Volevo solo sottolineare che PresentaionSources non sono collegati a elementi visivi finché non sono completamente caricati. Quindi se nel tuo costruttore stai impostando eventi che potrebbero essere attivati ​​prima che l'elemento visivo che stai tentando di chiamare PointFromScreen sia pronto per essere visualizzato sullo schermo, allora otterrai questo errore. Mentre come accennato prima si può avvolgere il metodo in qualcosa di simile:

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

si potrebbe anche non prendere in considerazione chiamando il metodo fino a quando si è sicuri che la visuale è stato il rendering sullo schermo almeno una volta.

+0

Non è possibile restituire null perché Point è un tipo di valore non annullabile. Forse vuoi restituire qualcosa come "return new Point()" – dontbyteme

1

L'eccezione può verificarsi perché visivo viene scartato ma ancora in memoria a causa di una perdita di memoria.

ho avuto un problema simile. Ho trovato l'eccezione che si verifica in un oggetto visivo che doveva essere raccolto dalla spazzatura. La risoluzione delle perdite di memoria nell'aspetto visivo ha risolto il problema.

+0

come hai risolto la perdita di memoria? – user5944566

+0

Ho usato uno strumento per trovare e correggere le perdite. Puoi utilizzare uno dei tanti strumenti, ad es. dotMemory, memprofiler. –

2

Ho trovato che è possibile testare prima di chiamare PointFromScreen per la protezione contro il InvalidOperationException.

Problemi correlati