2010-05-09 6 views
13

Sto tentando di visualizzare una pagina HTML con codice JavaScript incorporato all'interno di un controllo System.Windows.Forms.WebBrowser. Si prevede che il codice JavaScript interagisca con l'ambiente di incorporamento tramite l'oggetto window.external. Prima di invocare un metodo su window.external, JavaScript deve verificare l'esistenza del metodo. Se non è presente, il codice dovrebbe richiamare un metodo di fallback generico.Il metodo senza argomento su window.external viene richiamato durante il controllo con typeof

// basic idea 
if (typeof(window.external.MyMethod) != 'undefined') { 
    window.external.MyMethod(args); 
} else { 
    window.external.Generic("MyMethod", args); 
} 

Tuttavia, il controllo di un metodo senza argomenti con typeof sembra richiamare il metodo già. Cioè, se MyMethod accetta qualsiasi numero positivo di argomenti, il codice sopra funzionerà perfettamente; ma, se MyMethod è un metodo senza argomento, l'espressione typeof(window.external.MyMethod) non verificherà il suo tipo ma lo invocherà anche.

C'è qualche soluzione a questo comportamento? Posso in qualche modo sfuggire all'espressione window.external.MyMethod per impedire il verificarsi della chiamata al metodo?

+0

Hai provato a utilizzare typeof come operatore anziché come funzione? 'typeof window.external.MyMethod! ==" undefined "' –

+0

Chiunque risponda a questa domanda deve ** provare la propria soluzione con 'window.external' su IE ** - metodi regolari di test per l'esistenza di un oggetto su Javascript do non funziona per 'window.external'. – funkybro

risposta

9

non ho debug vostra situazione esatta, ma credo che i miei poteri psichici possono capire che cosa sta succedendo qui.

Il JScript lingua fa una distinzione tra uso di una funzione e mera menzione di esso. Quando dici

x = f; 

che dice "assegna un riferimento alla funzione identificata da f alla variabile x". Lo menziona f. Per contro,

x = f(); 

utilizza f. Significa "chiama la funzione identificata da f e assegna il valore restituito a x".

In breve, le funzioni in JScript sono essenzialmente quelle che potremmo pensare come proprietà del tipo delegato in C#.

Alcune lingue non fanno questa distinzione. In VBScript, se si dice x = f e f è una funzione, ciò significa chiamare la funzione, come x = f(). VBScript non fa una distinzione forte sintatticamente tra l'uso e la menzione di una funzione.

Il modo in cui tutto questo è implementato è l'utilizzo di COM; in particolare, utilizziamo l'automazione OLE. Quando si invia un campo di un oggetto per ottenere il suo valore, il motore JScript passa i flag che significano "property get" o "method invoke", a seconda che sia stato usato o menzionato.

Ma supponiamo che il tuo oggetto sia stato spedito con l'aspettativa che sarebbe stato chiamato da VB. Forse è stato scritto in VB. È perfettamente ragionevole e legale per un oggetto VB dire "oh, vedo che mi chiedi il valore di questo metodo.Dal momento che non capisco la differenza tra menzionare un metodo e usarlo, lo invocherò non importa quale bandiera passi ".

Non so se c'è una soluzione, ma sarei pronto a scommettere tanto quanto un dollaro che ciò che sta accadendo è l'oggetto invocato è supponendo che il chiamante desidera semantica VB.

+0

Ciao Eric, grazie per la tua eccellente risposta. Mi aspettavo che succedesse qualcosa del genere dietro le quinte da quando ieri ho letto il tuo commento sul blog del 2004 (http://discuss.techinterview.org/default.asp?joel.3.18644.7). Immagino che la roba della COM sia implementata da qualche parte all'interno del controllo WebBrowser, vero? Non sarò in grado di applicare un'altra gestione della ricerca?Oppure posso contrassegnare esplicitamente un metodo come "COM visibile come metodo e non come proprietà"? – janko

+0

In questo caso, puoi provare a giocare con l'implementazione di 'IDispatch' nella tua classe C#. Innanzitutto, proverei l'attributo 'IDispatchImpl': prova a impostarlo su' CompatibleImpl' e 'InternalImpl' e verifica se i due metodi funzionano. Oppure, puoi fornire la tua implementazione di 'IDispatch' - contrassegna il tuo oggetto' [ClassInterface (ClassInterfaceType.None)] 'e fallo implementare in modo esplicito' IDispatch'. Sospetto anche (non so davvero) che l'IDynamicObject di .NET 4.0 possa essere usato per il mapping di 'IDispatch'. –

-1

In realtà non sono sicuro che possa essere d'aiuto, ma prova window.external["MyMethod"].

Se ciò non risolve il problema, provare a memorizzare questo valore in una variabile, quindi controllare solo il tipo di tale variabile. Vedi se questo aiuta.

+0

Purtroppo nessuna variante funziona. 'window.external [" MyMethod "]' lo invoca, così come 'var f = window.external [" MyMethod "]'. – janko

0

provare uno di questi

/* Methods for feature testing 
* From http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting 
*/ 
function isHostMethod(object, property){ 
    var t = typeof object[property]; 
    return t == 'function' || 
    (!!(t == 'object' && object[property])) || 
    t == 'unknown'; 
} 

function isHostObject(object, property){ 
    return !!(typeof(object[property]) == 'object' && object[property]); 
} 

if (isHostObject(window.external, "MyMethod")) {.... 
+0

Ciao Sean, anche il tuo 'isHostMethod' non funziona. La riga 'oggetto [proprietà]' invoca ancora il metodo. – janko

6

ho trovato questo

if ('MyMethod' in window.external) 

non invocare MyMethod

+0

Ma questo non aiuta molto, lo script fallirà se 'window.external' non è presente. – funkybro

+0

@funkybro In tal caso, tutto ciò che devi fare è aggiungere un controllo extra, ad es. 'if (window.external && 'MyMethod' in window.external)'. – erdomke

+0

true, tuttavia se vedi la mia risposta qui di seguito che facendo semplicemente 'window.external' fallirai su IE. – funkybro

0

questo effetto può essere visto in Internet Explorer desktop. Uno script come ad esempio:

for (var i in window) { 
    console.log('window.' + i + ' = ' + window[i]); 
} 

fallirà non appena external è raggiunto.

Sembra che window.external non sia un normale oggetto Javascript, sia un oggetto VBScript.

dichiarazioni Così come la window.external e window['external']sono quindi VBScript dichiarazioni - e, come dice Eric L, window.external in VBScript è equivalente a window.external().

Possente confusione. Sembra anche che questo sia l'unico oggetto che si comporta in modo simile su Internet Explorer.

Per cross-browser applicazioni web mobili che fanno uso di Internet Explorer mobile di window.external.Notify() per comunicare con nativo su Windows Phone 8, ma che potrebbe anche voler impostare document.location su iOS, il test per l'esistenza di window.external.Notify sembrerebbe logico - ma non funziona per questo motivo

Non ho trovato un modo per impedirlo; succede ancora quando si specifica type="text/javascript" nel tag script.

0

Quindi l'unica scelta è una soluzione: 1) Basta non utilizzare le funzioni dei parametri 0. 2) Effettuare una funzione di controllo (prendendo un parametro) per rilevare se c'è un esterno a cui chiamare.

if (typeof(window.external.HasExternal(null)) != 'undefined') 

e verificare che invece della funzione se le funzioni esterne sono o là o no lì. 3) Per ogni funzione senza parametri, utilizzare un parametro fasullo o aggiungere una funzione di controllo dei parametri per esso se il codice esterno varia in base alle funzioni supportate.

Problemi correlati