WebUI.NET icon indicating copy to clipboard operation
WebUI.NET copied to clipboard

Csharpify this lib

Open mitchcapper opened this issue 11 months ago • 7 comments

Thanks for putting this together, WebUI looks interesting, hopefully this makes it friendlier to use. Sorry for such a large set of changes but they kind of stack.

Added to match the normal API calls (not rename their function): public unsafe bool Script(string javaScript, uint timeout_secs, Span<Byte> buffer)

Use Span for better memory efficiency and less allocation. Use a memory pool for alleviating the need for the library consumer to handle buffers if they do not want to example: public async Task<T?> ScriptEvaluate<T>(string javascript, TimeSpan? timeout = null, bool? stringReturnsAreSerialized = null)

That function also handles basic de-serialization to support various return types.

Moved this and future calls to use Task, even i the native library doesn't yet have async style calls we can still run on background threads and avoid UI wait.

Simplified event binding to bind click events: public void RegisterOnClick(Action<string> OnClick, String domId)

Added direct method binding with: public void RegisterBoundFunction(LambdaExpression methodExpression, String OverrideRegisteredName = null, object OverrideInstance = null) This is a heavier function. It allows you to bind any static or instance method into the Javascript namespace (at least it should, I don't get why the interface bind calls only are accessible via the "webui.call" functionality). If this isn't fixed in the base library can work around just be creating our own JS alias. It automatically will attempt to convert all args to the correct format, and handles missing args properly. It supports binding an async function and will properly wait for you to return. Note this does result in an ugly .Wait() call in the code, but as webui doesn't have any deferrals yet for return values I don't think there is another great option. We could design all callbacks to run on a dedicated BG thread potentially if needed.

It takes Lambdas to allow for a very easy way to specify both the method and instance without having to use reflection as the caller.

Added calling javascript methods passing the args separately. I noticed there is the raw function but I didn't dive into exactly how all the raw data would have to be presented. This internally converts the call to a string, but it does it fairly robustly. That code is 100% not mine, just the great work of @amaitland from https://github.com/cefsharp/CefSharp the license is on the helper class page. If for some reason you want to rip that out you can throw away the class and rewrite the functions to do it another way (or just take a full string call again).

public async Task<T?> ScriptEvaluateMethod<T>(string javascriptMethod, params object[] args) This also automatically serializes the JS responses and can deserialize them on the c# side allow for complex arbitrary types to be passed. On the c# side my example uses a static class definition but if you just do ScriptEvaluateMethods<JObject> you can walk the JS like normal.

I'd suggest seeing what is required to get listed on the official site for the c# package. Looking at the other language libraries I think these changes make it one of the most advanced wrappers / friendly options available. I would try to stick to official function naming for the common calls but then as you add additional user helpers you can use different naming that seems more natural. This allows easy porting between WebUI languages.

Assume calls succeed throw exceptions if they don't.

Added a WPF demo project showing these features off. Note the WebUI.Window.UseSpecificDispatcher is a bit clunky. Could be done automatically when running with UI (and far easier if we can just assume we can access Application.Current.Dispatcher as we can use the invoke methods there and store the dispatcher in the constructor.

Hopefully these building block wrappers and tools can increase performance and make it easier for people to use the library. I love the low overhead idea of WebUI. While the API is also very basic because of it, hopefully this can show how rich experiences can be done with just wrapping those basic calls.

I would suggest using project references rather for WebUI .NET lib rather than the nuget style you were doing for examples. Will make debugging and editing code much faster.

Future considerations:

Using a JS Proxy class one could bind entire C# classes into the javascript namespace with decent ease. The proxy class would just change any calls to a middleman script (ie say webui.call("proxy_helper",bound_class_name,bound_func_name,args...)). That C# function would just use reflection to find the function on the class and convert the args as I currently do.

Could easily add binder for any HTML eventListener with just some wrapped JS to be able to bind to. Given the idea of this being used as a generic UI interface having only a 'click' handler is a bit silly.

Good luck, hope you continue to maintain this!

mitchcapper avatar Mar 12 '24 15:03 mitchcapper