1
\$\begingroup\$

I´m creating a game in XNA with my own UI and its controls/components. Currently I have some problems with the event handling. Let me tell me the way I do it right now. Every object is handles as a component (also the form itself). Each component can implement an interface with a container which can contain a list of components (and so on and so on). An example: I have a form. On this form there is a TabControl. In this TabControl there are different TabPages and in these pages there are buttons.

I now have to handle my events that when I click on the button, the overlaying controls should not fire an event (like OnClick etc.).

How can I easily do that? I have a current function which runs recursively but only on two levels depth or something.

Here is my current function which is not working as expected:

private Boolean HandleComponentList(IComponentList parent) { 
foreach (var singleItem in parent.Components.OrderByDescending(i => i.ID).Where(singleItem => singleItem.Visible))
{
    // Cast item to IComponentList.
    var castedList = singleItem as IComponentList;
    // If list is not null (so it implements IComponentList), call HandleComponentList for Components in this control first.
    if (castedList != null)
    {
        // If an event has been raised, break function.
        var eventFound = HandleComponentList(castedList);

        if (eventFound)
            return true;
    }

    // Only fire events if control is enabled.
    if (singleItem.Enabled)
    {
        // look for events.
    }
}

return false;

}

Would be great if someone has some suggestions! Thank you!

\$\endgroup\$
1
\$\begingroup\$

In the similar scenario i've used polling model (updating input every frame), composite pattern (which you already implemented) and rectangle hit detection.

Every frame visual tree root (GUIManager, in my case) polls its children, calling the Update with the mouse coordinates, until one of them reports that the mouse is inside of it. This control will also be the only one checking the mouse button states and raising events. Visual tree root code:

foreach(Component c in Children)
{
    if(c.Update(Mouse.X,Mouse.Y))
        break;
}

And the update method (simplified):

if (IsInside(Mouse.X, Mouse.Y))
{
    //mouse is ours, check buttons, raise events.
    return true;
}
else return false;

For the complex controls, you can just combine these two pieces of code, firstly asking all of your control's children, and if none of them returns true, then the parent will handle the mouse/raise events.

if (IsInside(Mouse.X, Mouse.Y))
{
    foreach(Component c in Children)
    {
        if(c.Update(Mouse.X,Mouse.Y))
            return true;
    }
    //mouse is over the parent control, but not over one of its childs.
    return true;
}
else return false;

This behaviour can be tweaked in case you will need to handle the mouse in several controls. For instance, you can return up some kind of class which will store Handled variable - this will be a sort of WPF bubbling event model. Also instead of the special GUIManager you can use one of your Component classes for uniformity.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.