I am using CEFSharp in one of my projects and all works perfectly fine so far.
I am still on V63 of CEFSharp (never touch a running system :-) )
I am using it in VB.NET
The bound object is created after CEFSharp initialisation within Public Sub New() as follows:
CefSharpSettings.LegacyJavascriptBindingEnabled = True
Dim obj As New BoundObject()
obj.browser = browser
browser.RegisterJsObject("bound", obj)
AddHandler browser.LoadingStateChanged, AddressOf obj.Browser_LoadingStateChanged
I am then after each "LoadingStateChanged" event of the browser execute a JS script with browser.ExecuteScriptAsync.....its basically an event listner that will fire the bound object when the event occurs (e.g. a mousclick).
This also so far works 100% OK....the event fires and calls the bound object and passes a variable to my VB.NET code via the bound object.
Now my problem is that after I load a new page the bound object is lost.
The event listner will try to call the bound object but I just get an error like "Uncaught ReferenceError: bound is not defined"
Looks like be loading a new page inside CEFSharp the bound object is lost.
I triead the above initialisation code also with FrameLoadEnd event instead, but it behaves exactly the same as LoadingStateChanged event.
Any clue anyone how I can handle (or renew) the bound object whenever I load a new website?
Thanks
Update:
In the meantime I tried the binding method V2 as recommended.
Using the following code for testing purpose:
'########### TEST CODE TEST CODE TEST CODE ##################
'try to use new binding V2 method by calling CefSharp.BindObjectAsync:
browser.ExecuteScriptAsync("CefSharp.BindObjectAsync(""myObject"");")
'now register object:
browser.JavascriptObjectRepository.Register("myObject", New BoundObject(), True)
'now do test execution of myObject:
browser.ExecuteScriptAsync("myObject(""test"");")
But still struggeling to get it working :-(
The last sugestion of amaitland solved the problem. it works now nicely across various sites. In principle I just replaced this two lines in my original working code:
Dim obj As New BoundObject()
obj.browser = browser
'browser.RegisterJsObject("bound", obj) 'replaced by next line (JS binding V2)
browser.JavascriptObjectRepository.Register("bound", obj, True, Nothing)
AddHandler browser.LoadingStateChanged, AddressOf obj.Browser_LoadingStateChanged
And then later within the Sub that handles the browser_LoadingStateChangedAsync event I just added this line beofre any other injected JS:
'use new binding V2 method by calling CefSharp.BindObjectAsync:
browser.ExecuteScriptAsync("CefSharp.BindObjectAsync(""bound"");")
I hope this helps others using CEFsharpin VB.NET if they come across the same problem.
For anyone trying to do the same thing in C# (like me):
Browser.JavascriptObjectRepository.Register("myObject", interf, true);
Browser.LoadingStateChanged += (s, a) =>
{
if (a.IsLoading) return;
Browser.ExecuteScriptAsync("CefSharp.BindObjectAsync(\"myObject\");");
};
I've added checking the IsLoading state, as there is no reason to bind the object when the browser starts loading (at least in my use case).
Related
When cloning a button at runtime using Instantiate(), which contained listeners on it's onClick event, the listeners are not present in the clone.
The behaviour can be tested by having a Canvas with a button and this script attached:
void Start () {
var button = transform.GetChild (0);
button.GetComponent<Button> ().onClick.AddListener (new UnityAction(() => Debug.Log("Event triggered!")));
var button2 = Instantiate (button);
button2.SetParent (transform);
}
The cloned button will not print anything to the console when clicked.
Is there a way to clone a GameObject so that it retains event listeners?
Runtime listeners are not persistent and then not serialized. As a result they are not passed on when you clone the button.
Either you'd have to add the method to a script and attach the script to your prefab for it to be serialized along or assign it by code like you do for the first one.
Instantiation. When you call Instantiate() on either a prefab, or a
gameobject that lives in the scene, or on anything else for that
matter (everything that derives from UnityEngine.Object can be
serialized), we serialize the object, then create a new object, and
then we “deserialize” the data onto the new object. (We then run the
same serialization code again in a different variant, where we use it
to report which other UnityEngine.Object’s are being referenced. We
then check for all referenced UnityEngine.Object’s if they are part
of the data being Instantiated(). If the reference is pointing to
something “external” (like a texture) we keep that reference as it
is, if it is pointing to something “internal” (like a child
gameobject), we patch the reference to the corresponding copy).
http://blogs.unity3d.com/2014/06/24/serialization-in-unity/
As for AddListener
This function adds a "non persistent" delegate, which means it will not show up in the inspector, and will be forgotten when you exit play mode in the editor. These differ from "persistent" listeners which you can add during edit-time in the inspector, and which persist between edit and play mode.
https://docs.unity3d.com/ScriptReference/Events.UnityEvent.AddListener.html
For those reasons, I assume the non-persistent is not serialized and then not passed to the cloned object.
I added a new method to the CustVendPaym class called sendersBankCompanyStatementName of type BankCompanyStatementName.
This is the code of said method:
public BankCompanyStatementName sendersBankCompanyStatementName(BankCompanyStatementName _sendersBankCompanyStatementName = sendersBankCompanyStatementName)
{
sendersBankCompanyStatementName = _sendersBankCompanyStatementName;
return sendersBankCompanyStatementName;
}
I added the definition in the classDeclaration method:
BankCompanyStatementName sendersBankCompanyStatementName;
Then in the method vendPaym in the VendOutPaym class, a new instance of VendPaym (which extends CustVendPaym) is created:
vendPaym = new VendPaym();
//A bunch of properties are set then one I created:
vendPaym.sendersBankCompanyStatementName (bankAccountTable.BankCompanyStatementName);
If I break there, I see the assignment with the value I'm expecting working correctly, but then the debugger (watch) never actually shows the new property I added with the value that's supposed to be in it.
Then if I just continue code execution, the AOS server in which I'm developing just crashes :|
Any ideas, am I doing something obviously wrong ?
Thanks.
EDIT: If I rollback my changes (that is deleting the newly added method and removing any references to it) everything works as it was before.
Have you compiled forward the CustVendPaym class?
I am an absolute beginner on ASP.net (VB.) Please pardon me if the question is too obvious for the experienced members.
I tried to make a simple WebRequest in the async mode in case the target URL takes long to provide the data. In my code below, I just want to see if the callback block (RespCallback) is called correctly every time. If all goes well, lblResult should have the string '123' appended to it every time I click the button which calls the 'GetData' sub.
However, the lblResult only shows 123 after the first click. After the subsequent click, the lblResult only gets appended with '12', as if RespCallback is never called. When I tried to debug this in Visual Studio, the execution actually stepped right into the RespCallback part and the lblResult.Text watch actually shows '123123' but the resulting Web page always shows only '12312'
I am sure I am missing something basic here, but I just don't know what. I was even guessing that it has to do with browser cache (hence the result changes for the second time) but I don't know how to fix that either.
Can someone please help? Thanks in advance.
Jim
Dim myWebRequest As WebRequest
Public Shared allDone As New ManualResetEvent(False)
Private Shared BUFFER_SIZE As Integer = 1024
Public Class RequestState
' This class stores the state of the request
Private Shared BUFFER_SIZE As Integer = 1024
Public requestData As StringBuilder
Public bufferRead() As Byte
Public request As WebRequest
Public response As WebResponse
Public responseStream As Stream
Public Sub New()
bufferRead = New Byte(BUFFER_SIZE) {}
requestData = New StringBuilder("")
request = Nothing
responseStream = Nothing
End Sub ' New
End Class ' RequestState
Public Sub GetData(Sender As Object, Args As System.EventArgs)
lblResult.Text += "1"
myWebRequest = WebRequest.Create(dataURL)
Dim myRequestState As New RequestState()
myRequestState.request = myWebRequest
' Start the asynchronous request.
Dim asyncResult As IAsyncResult = CType(myWebRequest.BeginGetResponse(AddressOf RespCallback, myRequestState), IAsyncResult)
lblResult.Text += "2"
allDone.WaitOne()
End Sub
Private Sub RespCallback(asynchronousResult As IAsyncResult)
lblResult.Text += "3"
allDone.Set()
End Sub
I don't know VB so it's hard to read for me but I'm suspecting GetData is your onClick handler.
First thing that is not right is that you have Shared members. Why your reset event is Shared? It makes all requests use the same object.
Basically Your code with ManualResetEvent won't work because after first allDone.Set(), your object remains set (as long as web application lives). To get "123" every time you should add allDone.Reset() after allDone.WaitOne().
In Your situation web request returns to client before RespCallback is called every time except first call (when your reset event is in non-signaled state).
AutoResetEvent resets automatically. That's why it worked.
But! You can't do this this way. Making your ResetEvent Shared you make all request use the same object. When more than one request will be processed by your application at the same time you will get undetermined behavior.
Remove Shared from your code. Than your code will work (but not asynchronously) without allDone.Reset() and without AutoResetEvent. But it will provide known results (not depending on amount of requests).
About asynchronous call (now that we have code "working"). Well. There is no async request to your web page. allDone.WaitOne() waits until your async webRequest finish. So basically you could just as well do synchronous request.
You need a special pattern for asynchronous web pages. You can read how to do this here.
But i'm not sure it's what you wanted. Do you want your request to be called asynchronously so that it will not use server resources or do you want to display some message to the user (like "Data is being downloaded...") while your web page will remain fully responsible?
If it's the second one you should use AJAX functionality (Like UpdatePanel or using JavaScript directly). You can read about it here.
Couple things to check:
If your label is a fixed width, then it's possible the text is being clipped
If you are using an UpdatePanel, you will need to set its mode to 'Conditional' and call Update() on it in the RespCallback callback method so that the UI gets refreshed with the latest label text value.
I'm trying to eliminate a VB.NET button on my aspx page. Trying to use javascript and ajax to execute the same code my vb had.
I put in a script manager, set EnablePageMethods to true, added a static subroutine, and referred to it in my javascript function (BTW -- this seems a lot of work just to execute an existing subroutine). The javascript calls my code-behind and it almost works.
Problem is, now I'm getting a NullReferenceException when SimulatePrintBatchClick tries to do anything with the controls.
Error is 'Object reference not set to an instance of an object', line is 'pnlVars.Controls.Clear'
Here's the code from UW.aspx:
<WebMethod()> _
Public Shared Sub PrintBatchFromJSWM()
Dim UWI As New UW
UWI.SimulatePrintBatchClick()
End Sub
Sub SimulatePrintBatchClick()
Dim Client As New LetterWriterClient
'Run ExStream and get the PDF File
Globals.PDF_Data = Nothing
Globals.PDF_Data = Client.ProcessDatFile(Session("SessionID").ToString)
'Reload the form -- turn off all controls, initialize variables and make the PDF iFrame visible
pnlVars.Controls.Clear() 'Bombs out on THIS line of code
pnlPDF.Visible = True
Me.SendToBach.Visible = False
Session.Contents("LetterVariables") = Nothing
Session.Contents("PolicyInformation") = Nothing
Session.Contents("Submitted") = True
Response.Redirect("UW.aspx")
End Sub
Funny, when I run the above code in PrintBatch_Click it all executes just fine. I really don't understand why it bombs out as a subroutine.
Perhaps this is not the way to do this, but I'm at a loss for finding a different way. Originally this code was handled by an ASP/VB button, but the specs have called for it to be deleted.
Any way I can get the above code to do it's job?
Thanks,
Jason
You cannot use any server controls in WebMethod or AjaxMethod as they are not part of Page life cycle, access these controls in Javascript.
Ran into an “Out of Stack Space” error trying to serialize an ASP.Net AJAX Array object.
Here is the scenario with simplified code:
Default.aspx
MainScript.js
function getObject(){
return new Array();
}
function function1(obj){
var s=Sys.Serialization.JavaScriptSerializer.serialize(obj);
alert(s);
}
function function2(){
var obj=getObject();
var s=Sys.Serialization.JavaScriptSerializer.serialize(obj);
alert(s);
}
Content.aspx
ContentScript.js
function serializeObject(){
var obj=window.top.getObject();
window.top.function1(obj); // <– This works fine
obj=new Array();
window.top.function1(obj); // <– this causes an Out of Stack Space error
}
The code for the sample pages and JavaScript is here.
Posting the code for the aspx pages here posed a problem. So please check the above link to see the code for the aspx pages.
A web page (default.aspx) with an IFrame on that hosts a content page (content.aspx).
Clicking the “Serialize Object” button calls the JavaScript function serializeObject(). The serialization works fine for Array objects created in the top window (outside the frame). However if the array object is created in the IFrame, serialization bombs with an out of stack space error. I stepped through ASP.Net AJAX JS files and what I discovered is, the process goes into an endless loop trying to figure out the type of the array object. Endless call to Number.IsInstanceOf and pretty soon you get an out of stack error.
Any ideas?
This problem happens because Sys.Serialization.JavaScriptSerializer can't serialize objects from others frames, but only those objects which where instantiated in the current window (which calls serialize() method). The only workaround which is known for me it's making clone of the object from other frame before calling serialize() method.
Example of the clone() methode you can find here (comments in Russian):
link text
I converted your example to a set of static html files, and dowloaded the standalone Microsoft Ajax Library 3.5 to test with. It didn't have issue on either Firefox 3 or IE 7, but I did notice the first alert box displayed [] (an array) and the second {} (an object).
Then, I converted your new Array() code to:
var obj = [];
obj.push(1);
and after that, I got [1] and {"0", 1} is the alert boxes. I don't think the bug is with JavaScriptSerializer, but something to do with passing objects across frames.
I have no way of testing your code right now, but it looks like a bug in JavaScriptSerializer.serialize to me. My guess is that it tries to do some kind of type checking on the array via the CLR and that it doesn't handle an empty array properly.
Have you tried to add an item of a serializable type to the array in your code? If so, what happens?