v2.48
How to handle events

Overview

Renga API allows developers to handle various events that occur during the application's lifecycle. Plugins can respond to user actions, application state changes, selection changes, etc. Renga SDK provides event source classes for different types of events, which allow subscribing to events and providing custom handling logic.

The implementation of event handling varies between the SDK for supported languages. C++ and C# SDK provide ...EventSource helper classes, which serve as wrappers around the native COM event subscription mechanism. Since Renga API is built on COM, you can also create your own event handlers using the IConnectionPoint mechanism directly.

How to subscribe on events

To subscribe on events, first you need to create an event source and pass to its constructor the object whose events you want to subscribe on.

C++

In C++ you should call the appropriate Subscribe... method and pass any callable object, such as function, lambda expression, etc. All Subscribe... methods return unique Id of the just subscribed callback as int value.

void OnProjectClosed() { /* Handle the project closed event */ }
bool initialize(const wchar_t* pluginDir) override
{
auto pApplication = Renga::CreateApplication();
...
// Create ApplicationEventSource and pass pApplication to its ctor
m_pAppEventSource = std::make_unique<Renga::ApplicationEventSource>(pApplication);
// Subscribe on event with function
m_pAppEventSource->SubscribeProjectClosed(OnProjectClosed);
// Subscribe on event with lambda
m_pAppEventSource->SubscribeProjectCreated([]()
{
// Handle the project created event
});
}

C#

In C# you should call += operator on appropriate event field and pass callback function or lambda to it. Read more about C# events mechanism.

private void OnProjectClosed() { /* Handle the project closed event */ }
public bool Initialize(string pluginFolder)
{
var application = new Renga.Application();
...
// Create ApplicationEventSource and pass application to its ctor
m_appEventSource = new Renga.ApplicationEventSource(application);
// Subscribe on event with function
m_appEventSource.ProjectClosed += OnProjectClosed;
// Subscribe on event with lambda
m_appEventSource.ProjectCreated += () =>
{
// Handle the project created event
});
}

You can subscribe multiple callbacks on a single event. Each callback will be invoked in the order they were added.

Note
In an event handler, you cannot modify the source object in such a way that the current event is raised again. For example, you cannot change selection in OnModelSelectionChanged event handler.

How to unsubscribe from events

To stop handling event with a specific callback, you can unsubscribe it from the event.

C++

In C++ you should call the appropriate Unsubscribe... method and pass unique callback Id to it. You can get an unique callback Id as return value of appropriate Subscribe... method.

// Subscribe on the event
int projectClosedCallbackId = m_pAppEventSource->SubscribeProjectClosed(OnProjectClosed);
...
// Unsubscribe from the event
m_pAppEventSource->UnsubscribeProjectClosed(projectClosedCallbackId);

C#

In C# you should call -= operator on appropriate event field and pass subscribed callback function to it. Read more about C# events mechanism.

// Subscribe on the event
m_appEventSource.ProjectClosed += OnProjectClosed;
...
// Unsubscribe from the event
m_appEventSource.ProjectClosed -= OnProjectClosed;
Note
You can also delete the event source object to unsubscribe from all its events.

How to manage event source lifetime

This section provides the basic rules for managing the lifetime of an event source:

  • When you create an event source, it stores an internal reference to the source object that you pass to its constructor, so you do not need to keep the original source object alive separately. The event source will keep it alive for you.
  • Event source objects must remain alive as long as your plugin needs to handle events. If an event source is destroyed, all event subscriptions are automatically unsubscribed and no further events will be delivered.
  • Event subscriptions must be unsubscribed before the source object becomes invalid. If an event source continues to exist after its source object has been destroyed, Renga may attempt to deliver events to a non-existent object, leading to crashes or undefined behavior. To ensure event sources are destroyed before their source objects become invalid, use Before... events or IPlugin::Stop method.

C++

The following example shows how to properly manage an event source in C++ using std::unique_ptr. Note that the event source is stored as a class member and explicitly destroyed in stop():

#include <Renga/ApplicationEventSource.hpp>
...
class SomePlugin : public Renga::IPlugin
{
public:
bool initialize(const wchar_t* pluginDir) override
{
auto pApplication = Renga::CreateApplication();
// Create ApplicationEventSource
m_pAppEventSource = std::make_unique<Renga::ApplicationEventSource>(pApplication);
// Subscribe on events
m_pAppEventSource->SubscribeProjectClosed(OnProjectClosed);
m_pAppEventSource->SubscribeProjectCreated([]()
{
// Handle the project created event
});
}
void stop() override
{
// Delete ApplicationEventSource when plugin stopped
m_pAppEventSource.reset();
}
private:
void OnProjectClosed() { /* Handle the project closed event */ }
// Any event source should stay alive as long as you need to handle the events
std::unique_ptr<Renga::ApplicationEventSource> m_pAppEventSource;
};
The interface for plugin.
Definition IPlugin.h:40

C#

In C#, event sources implement the IDisposable interface. Note that the event source is stored as a class member and explicitly calls .Dispose() in Stop():

public class SomePlugin : public Renga.IPlugin
{
// Any event source should stay alive as long as you need to handle the events
private Renga.ApplicationEventSource m_appEventSource;
public bool Initialize(string pluginFolder)
{
var application = new Renga.Application();
// Create ApplicationEventSource
m_appEventSource = new Renga.ApplicationEventSource(application);
// Subscribe on events
m_appEventSource.ProjectClosed += OnProjectClosed;
m_appEventSource.ProjectCreated += () =>
{
// Handle the project created event
});
}
public void Stop()
{
// Delete ApplicationEventSource when plugin stopped with Dispose() method
m_appEventSource.Dispose();
}
private void OnProjectClosed()
{
// Handle the project closed event
}
}

See also

Related samples

  • Buttons
  • ModelSelection
  • ModelViewEvents
  • SystemEvents