Data Sharing

Enabling the Channel Selector

The .NET Channels API is enabled by default. The Channel Selector for your window is usually enabled or disabled via system or app configuration. For .NET apps, you can also enable or disable the Channel Selector at runtime when registering your window as an io.Connect Window:

var options = io.GlueWindows.GetStartupOptions() ?? new GlueWindowOptions();

// Enabling the Channel Selector at runtime.
options.WithChannelSupport(true);

// Registering a flyer window.
IGlueWindow myWindow = await io.GlueWindows.RegisterWindow(this, options);

// From the window object you can get the context of the current Channel,
// which you can use to retrieve data from the current Channel, subscribe for updates, and publish data.
IGlueChannelContext channelContext = myWindow.ChannelContext;

Channel Discovery

To retrieve a list of all currently known Channels, use the GetChannels() method:

IGlueChannel[] channels = io.Channels.GetChannels();

To retrieve a specific Channel by name, use the AwaitChannel() method and provide the Channel name:

IGlueChannel channel = await io.Channels.AwaitChannel("Green");

Instead of the Channel name, you can also provide a lambda expression to AwaitChannel(). This allows you filter the available Channels and retrieve the one in which you are interested:

IGlueChannel channel = await io.Channels.AwaitChannel(channel => IsChannelInteresting(channel));

You can also use the Subscribe() method providing a lambda expression as an argument to retrieve and handle all Channels. The lambda expression will be invoked for all currently existing Channels, as well as for any newly created ones:

io.Channels.Subscribe(channel => HandleChannel(channel));

Joining Channels

To join a Channel, use the JoinChannel() method and pass the Channel object of the Channel you want to join as an argument:

IGlueChannelContext channelContext = io.Channels.JoinChannel(channel);

The returned Chanel context object can then be used for retrieving, publishing, and subscribing for Channel updates. The Channel context can be obtained also from the window object when enabling the Channel Selector during window registration.

Subscribing for Channel Updates

To subscribe for updates of the current Channel, use the Subscribe() method of the Channel context object. The Subscribe() method accepts an instance of the LambdaGlueChannelEventHandler class as a first argument. As a second argument, it accepts a dot-separated string path pointing to the property in the Channel context to which to subscribe (e.g., "prop1.prop2").

To provide a lambda expression for handling Channel updates, instantiate the LambdaGlueChannelEventHandler class. Pass the lambda expression as a first argument to the class constructor. The lambda expression will be invoked with the Channel context, the Channel object and an object describing the update as arguments.

It's possible to create typed as well as untyped subscriptions for Channel updates.

Typed Subscriptions

When subscribing for updates to a property or to an entire object in a Channel context, you can specify the type of the data you are expecting to be returned. Typed subscriptions enable easier handling of Channel updates.

Typed subscription for updates to a specific property:

channelContext.Subscribe(
    new LambdaGlueChannelEventHandler<double>(
        (context, channel, update) =>
        {
            // The updated value is of the required type.
            double newPrice = update;
            // Handle the updated property with your custom logic.
            Console.WriteLine($"New price of instrument is ${newPrice}.");
        }
    ),
    "instrument.price"
);

Typed subscription for updates to the entire object:

channelContext.Subscribe(
    new LambdaGlueChannelEventHandler<Instrument>(
        (context, channel, update) =>
        {
            // Updated value is of the requested type.
            Instrument instrument = update;
            // Handle the updated object with your custom logic.
            HandleInstrument(instrument);
        }
    ),
    "instrument"
);

Untyped Subscriptions

For untyped subscriptions, the update object passed as a third argument to the provided handler will contain the following properties:

Property Type Description
Added DeltaItem[] List of objects describing all newly added properties.
Deltas DeltaItem[] List of objects describing all properties that have been changed in some way (added, removed, or updated).
Removed DeltaItem[] List of objects describing all removed properties.
Updated DeltaItem[] List of objects describing all previously existing properties whose values have been updated.

The following example demonstrates creating an untyped subscription to a property in the Channel context:

channelContext.Subscribe(
    new LambdaGlueChannelEventHandler(
        (context, channel, update) =>
        {
            // Previously existing properties whose values have been updated.
            DeltaItem[] updated = update.Updated;
            // Newly added properties.
            DeltaItem[] added = update.Added;
            // Removed properties.
            DeltaItem[] removed = update.Removed;

            foreach (DeltaItem update in updated)
            {
                Console.WriteLine($"Updated property: {update.Key}, new value: {update.After}, old value: {update.Before}.");
            }
        }
    ),
    "instrument"
);

Reading Channel Data

To retrieve data from a Channel context, use the GetValue() method of the Channel context object. It accepts as an argument a dot-separated string path pointing to the property in the Channel context whose value to retrieve (e.g., "prop1.prop2"). It's possible to retrieve data from a Channel context by reading individual properties or by reading entire typed objects.

The following example demonstrates retrieving the data from individual Channel context properties:

string firstName = channelContext.GetValue<string>("contact.name.fistName");
string lastName = channelContext.GetValue<string>("contact.name.lastName");

Console.WriteLine($"Contact: {firstName} {lastName}");

The following example demonstrates retrieving an entire typed object:

// Define the object type.
public class Contact
{
    public string firstName { get; set; }
    public string lastName { get; set; }
}

// Retrieve the entire object from the Channel context.
Contact contact = channelContext.GetValue<Contact>("contact");

if (contact is Contact)
{
    // Handle that object with your custom logic.
    HandleContact(contact);
}

Publishing Data

To update the Channel data, use the SetValue() method of the Channel context object. Provide the new data as a first argument, and as a second argument provide a dot-separated string path pointing to the property in the Channel context whose value to update (e.g., "prop1.prop2"). If the specified property doesn't exist, it will be created:

channelContext.SetValue(211.07, "instrument.price");

You can also update an entire object:

Instrument instrument = new Instrument
{
    symbol: "VOD.L",
    price: 213.42
};

channelContext.SetValue(instrument, "instrument");

Channel Events

The Channels API provides means for handling events related to updating the Channel data (see also Subscribing for Channel Updates) and changing the current Channel.

To provide handlers for both events, use the Subscribe() method of the Channel context object. The Subscribe() method accepts an instance of the LambdaGlueChannelEventHandler class as a first argument. As a second argument, it accepts a dot-separated string path pointing to the property in the Channel context to which to subscribe (e.g., "prop1.prop2").

To provide a lambda expression for handling Channel updates, instantiate the LambdaGlueChannelEventHandler class. Pass the lambda expression as a first argument to the class constructor. The lambda expression will be invoked when the Channel context is updated. It will receive the Channel context, the Channel object and an object describing the update as arguments:

channelContext.Subscribe(
    new LambdaGlueChannelEventHandler<double>(
        (context, channel, update) =>
        {
            double newPrice = update;

            Console.WriteLine($"New price of instrument is {newPrice}.");
        }
    ),
    "instrument.price"
);

To provide a lambda expression for handling Channel changes, instantiate the LambdaGlueChannelEventHandler class. Pass a null value as a first argument to the class constructor and the lambda expression as a second. The lambda expression will be invoked when the current Channel is changed, including when the window isn't joined to a Channel anymore. It will receive the Channel context, the new Channel, and the previous Channel as arguments:

channelContext.Subscribe(
    new LambdaGlueChannelEventHandler(
        null,
        // Callback for handling Channel changes.
        (context, newChannel, previousChannel) =>
        {
            Console.WriteLine($"New Channel: {newChannel ? newChannel.Name : "No Channel"}, Previous Channel: {previousChannel.Name}");
        }
    )
);

You can also provide both event handlers simultaneously:

channelContext.Subscribe(
    new LambdaGlueChannelEventHandler<double>(
        // Callback for handling Channel context updates.
        (context, channel, update) =>
        {
            double newPrice = update;

            Console.WriteLine($"New price of instrument is {newPrice}.");
        },
        // Callback for handling Channel changes.
        (context, newChannel, previousChannel) =>
        {
            Console.WriteLine($"New Channel: {newChannel ? newChannel.Name : "No Channel"}, Previous Channel: {previousChannel.Name}");
        }
    ),
    "instrument.price"
);