This is a C# port of the C++ Binding Sample and is built on top of the SlimDX Sample.
For instructions on deploying the sample, please read .NET Sample guides.
For a more detailed explanation of how binding works, you can check the Detailed Binding Guide
The .Net Binding sample demonstrates communication between the .Net application code and the JavaScript universe of the view.
The key points of the sample are
Handling Coherent.UI.View.BindingsReady
event
public MyViewListener(SlimDXApp app)
{
this.ReadyForBindings += this.RegisterBindings;
}
Registering delegates to handle events and calls triggered from JavaScript Binding
public void RegisterBindings(int frame, string url, bool isMainFrame)
{
if (isMainFrame)
{
m_View.BindCall("ApplyOptions", (Action<Options>)Game.Options.ApplyOptions);
m_View.BindCall("GetLatency", (Func<int>)Game.GetNetworkLatency);
m_View.BindCall("GetGameTime", (Func<int>)Game.GetGameTime);
m_View.BindCall("GetMath", (Func<BoundObject>)(
() => BoundObject.BindMethods(new MyMath())
));
m_View.RegisterForEvent("ViewReady", (Action)this.ViewReady);
}
}
The HTML and Javascript code for this sample is in Coherent/Samples/UI/bin/html/binding.html.
When the document has been loaded and C# handlers have been registered the Ready
event is fired.
engine.on('Ready', function () {
engine.trigger('ViewReady');
engine.call('GetMath').then(function (math) {
window.MyMath = math;
engine.trigger('gameConsole:AddCommand', 'sum', 'computes the sum of its arguments', function (line) {
var numbers = line.split(/\s+/).map(Number);
numbers.splice(0, 1);
window.MyMath.Sum(numbers).then(function (sum) {
engine.trigger('gameConsole:Trace', 'The sum of', numbers, 'is', sum);
});
});
engine.trigger('gameConsole:AddCommand', 'avg', 'computes the average of its arguments', function (line) {
var numbers = line.split(/\s+/).map(Number);
numbers.splice(0, 1);
window.MyMath.Average(numbers).then(function (avg) {
engine.trigger('gameConsole:Trace', 'The average of', numbers, 'is', avg);
});
});
});
});
This actually triggers
private void ViewReady()
{
Game.Options.SetView(m_View);
m_View.TriggerEvent("OpenOptions", Game.Options.Options);
}
Options
is a C# type and must be exposed to JavaScript.
struct Options
{
public string Backend;
public uint Width;
public uint Height;
public string Username
{
get {
return System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();
}
}
[CoherentProperty("NetworkPort")]
public uint NetPort { get; set; }
}
- Note
- By default all public fields and properties of a C# type are visible to CoherentUI with the same names they have in *.Net*.
JavaScript functions bound to event "OptionOptions"
receive an JavaScript object with the described properties and values taken from the C++ options object given to Coherent::UI::View::TriggerEvent
.
function openOptions(options) {
$("#options").dialog( "open" );
$("#backend").text(options.Backend);
$("#gameWidth").val(options.Width);
$("#gameHeight").val(options.Height);
$("#user").text(options.Username);
$("#netPort").val(options.NetworkPort);
}
engine.on("OpenOptions", openOptions);
If JavaScript calls .Net function that takes an Options
as an argument, the JavaScript object must have a property __Type
with the AssemblyQualifiedName
or at least the FullName
of the type. For more details see User Defined Types .
function onApplyButton(){
var options = {};
options.__Type = gameOptionsTypeName;
options.Backend = $("#backend").text();
options.Width =
Number($(
"#gameWidth").val());
options.Height =
Number($(
"#gameHeight").val());
options.Username = $("#user").text();
options.NetworkPort =
Number($(
"#netPort").val());
engine.call("ApplyOptions", options);
}
This sample also shows how to use binding of .Net methods. For detailed explanation see Exposing object methods .
The sample exposes an instance of MyMath
to JavaScript.
class MyMath
{
public double Sum(double[] numbers)
{
return numbers.Sum();
}
public double Average(double[] numbers)
{
return numbers.Average();
}
}
When the game is up and running, we request the MyMath
instance, store it as a global object and register two console commands that use it.
engine.on('Ready', function () {
engine.call('GetMath').then(function (math) {
window.MyMath = math;
engine.trigger('gameConsole:AddCommand', 'sum', 'computes the sum of its arguments', function (line) {
var numbers = line.split(/\s+/).map(Number);
numbers.splice(0, 1);
window.MyMath.Sum(numbers).then(function (sum) {
engine.trigger('gameConsole:Trace', 'The sum of', numbers, 'is', sum);
});
});
engine.trigger('gameConsole:AddCommand', 'avg', 'computes the average of its arguments', function (line) {
var numbers = line.split(/\s+/).map(Number);
numbers.splice(0, 1);
window.MyMath.Average(numbers).then(function (avg) {
engine.trigger('gameConsole:Trace', 'The average of', numbers, 'is', avg);
});
});
});
});
To try out the commands press ~
to open the game console and type sum 40 2
.