How should an array be passed to a Javascript function from C#?
I use a WebBrowser object from WPF and I开发者_开发知识库'm calling some Javascript code in the page loaded in the browser like this:
myWebBrowser.InvokeScript("myJsFunc", new object[] { foo.Text, bar.ToArray<string>()});
Now, the js function is supposed to iterate over the elements of the second parameter (an array of strings) and do stuff accordingly. The only issue is that the parameter seems not to be passed as a js array.
For example,
alert(typeof theArray);
alerts "Unknown".
What is the proper way to pass an array as a parameter when invoking a js function from CSharp?
Maybe pass it as a json string instead and parse it in the js function
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var json = serializer.Serialize(bar.ToArray<string>());
myWebBrowser.InvokeScript("myJsFunc", new object[] { foo.Text, json });
js:
function myJsFunc(json) {
var data = JSON.parse(json);
// do something with it.
}
http://blogs.microsoft.co.il/blogs/pini_dayan/archive/2009/03/12/convert-objects-to-json-in-c-using-javascriptserializer.aspx
It's not solving the issue itself but it solves the problem if you have only one array to pass: you can send an arbitrary number of parameters to a JavaScript function, and access them through the arguments
special variable. It becomes analogous to a function accepting a variable number of arguments, with the same advantages and problems (for instance, you have to pass the array last, and as mentioned earlier you can only pass one).
Here's an example JavaScript function:
function foo()
{
var stringArgs = [];
for (var i = 0; i < arguments.length; i++)
stringArgs.push(arguments[i]);
// do stuff with stringArgs
}
And you'd call it from C# like this:
List<string> arguments = new List<string>();
arguments.Add("foo");
arguments.Add("bar");
webBrowser.InvokeScript("foo", arguments.ToArray());
In case you really want to squeeze every bit of performance out of the code you can avoid the deserialization by means of eval inside javascript. The concept is to structure the call like this:
((IHTMLWindow2)webBrowserControl.Document.Window.DomWindow).execScript("var returnValue = someFunction([ 'abc', 'xyz', '1', '2', '3' ], { foo: 'xyz', bar: 1 });"
Notice that we use .execScript which makes all the difference in the world. This is because contrary to .InvokeScript which would forcefeed the javascript method with string based arguments (which is what forces you to use eval on the javascript side), .execScript() gives us the ability to write arbitrary javascript code including what you see above (notice that the arguments are an explicit javascript array and a bag of properties). Now we can directly code arrays and objects and write them as arguments. In order to do that we just use Newtonsoft.Json to serialize arrays and objects:
class Test {
public string foo;
public int bar;
}
((IHTMLWindow2)webBrowserControl.Document.Window.DomWindow).execScript("var returnValue = someFunction(" +
JsonConvert.SerializeObject((new List<object>(2) { "abc", "xyz", 1, 2, 3 }).ToArray()) + ", " + JsonConvert.SerializeObject(new Test() { foo = "xyz", bar = 1 }) + ");");
Another thing is retrieving the resulting returned value:
string result = (string)webBrowserControl.Document.InvokeScript("eval", new object[] { @"returnValue;" }));
For your convenience you might want to write a utility method which iterates over the given parameters and serializes them properly, invokes the function and then retrieves the returned value.
You need to convert the array to a JS array first, something that looks like this:
["John", "Bob", "Sue"] // literal array
Two examples follow:
StringBuilder sb = new StringBuilder();
string[] stringArray = bar.ToArray<string>();
//Build the JS array.
sb.Append( "[");
for (int i = 0; i < stringArray.Length; i++)
{
sb.AppendFormat( "'{0}', ", stringArray[i] );
}
sb.Append( "]");
// Now send the array to the JS function.
myWebBrowser.InvokeScript("myJsFunc", new object[] { foo.Text, sb.ToString() });
You may want to remove the trailing , as well. Don't forget to import the appropriate libraries for StringBuilder, which I think is System.Text.StringBuilder;
or use, example two:
string[] stringArray = bar.ToArray<string>();
// or simpler to use string join.
string jsArray = "[" + String.Join( ",", stringArray ) + "]";
//
myWebBrowser.InvokeScript("myJsFunc", new object[] { foo.Text, jsArray });
精彩评论