In this lesson, you will learn how to handle events in Zebble, from user gestures to input controls and system wide events.
It will explain the problem with the traditional event model of C# in the modern world of asynchronous programming, and how Zebble's innovative approach will address them.
The standard event definition API in C# has been designed before the age of Task Parallel Library. Pretty much all .NET event handlers return a void as opposed to a Task. This means that it's not possible to await the code that subscribers register for an event.
The good news is that as Zebble has been designed in 2016, all of its events support asynchronous programming. You might notice that the Zebble events are members of type AsyncEvent as opposed to the traditional EventHandler type. The AsyncEvent type provides the pipework for defining, subscribing to and raising events.
Zebble UI events such as Tabbed, Swiped, etc, are in one of the following types:
To add event handlers you can use any of the following methods. Suppose you have a View object named MyView and you want to handle its LongPressed event. You have 2 options to attach an event handler. You can either use the Handle() method on the event object, or use the On method on the view.
// Option 2 (recommended):
MyView.On(x => x.LongPressed, HandlerMethodName);
Your event handler can be a task or void. Or you can use a lambda expression. If your event handler is a VOID instead of TASK returning method, then you must explicitly cast it to Action as for some reason the C# compiler is not smart enough to infer the right overload.
.On(x => x.LongPressed, MyTaskHandler)
.On(x => x.LongPressed, (Action) MyVoidHandler)
.On(x => x.LongPressed, () => ...(logic)...);
// handling code here...
// handling code here...
Some events provide arguments. For example, the Tapped event provides a point object to tell you exactly where on the object the user tapped. However, in many scenarios, you may not care about that. In Zebble, your event handlers don't have to accept arguments if they don't need it.
MyView.On(x => x.Tapped, MySecondHandler);
// I do need the parameter.
Task MySecondHandler(Point point)
You can use the RemoveHandler() method on an event object if you want to unsubscribe.
Though, when a view object is disposed, it will automatically unregister its event handlers. So you don't have to worry about keeping cyclic references between objects which could traditionally cause garbage collection issues.
By default, the event handlers will run on the same thread that raises the event. However, if you specifically need your handler to run on the UI thread you can use the HandleOn() method instead. This is only needed in very rare cases that you want to manipulate the native components directly, e.g. in platform-specific code.
If you want to create your own events, also you can use this model. The following shows the code pattern to implement it correctly.
// Simply define an instance of AsyncEvent to declare one.
public readonly AsyncEvent SpecialEvent = new AsyncEvent();
async Task SomewhereScenario()
// The following will invoke all the registered subscribers sequentially in the order they were subscribed.
// Alternatively, you can raise them in parallel
await SpecialEvent.Raise(inParallel: true);
// Make sure to dispose it
public override Dispose()
We want to create a simple sample that has a TextView and a SearchInput components. When the user types a string and selects Search button, the string is shown in TextView automatically.
First of all, we create a page named Page-5 with this Markup code:
<z-Component z-type="Page5" z-base="Templates.Default" z-namespace="UI.Pages"
z-partial="true" Title="About us" data-TopMenu="MainMenu" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<TextView Id="txt1" ></TextView>
<SearchInput Id="MySearchInput" on-Searched="ApplySearch" />
For implementing the ApplySearch method, you should go to Page-5.cs file:
public override async Task OnInitializing()
async Task ApplySearch()
txt1.Text = MySearchInput.Text;
// In this example I want to pass the keywords to an API to implement the search logic on the server.
The result page is same this image: