views:

296

answers:

3

Hi, I am new to professional programming, I am writing C# but I think this isn't exactly C# specific. Anyway, I want to ask what's the best way to enable/disable some controls amongst multiple controls under various different condition?

Let's say, there is a GUI with some rows, each represent a person. There are also some buttons, representing some actions, say, "Stand, Sit, Walk, Jump, Eat, Watch TV, Wake, Sleep" and there are some conditions, like if someone is sitting he can eat and watch tv(i.e. enable those button) but can't jump(disable it), if someone is standing he cant sleep........ and so on. Also, the state change is not solely based on an button click. Like, he might just wake up himself after some time or, say, finished eating.

It seems that the most naive way is to write the .Enabled = true/false; code for n states X m buttons times, and check it for every user or non user triggered state change. Is there some better/faster/less-error-prone way to do that?

Also, what are this sort of thing called? I don't know a proper term in English to describe it well and so I can't google it myself.... Please help. Thank you very much.

+1  A: 

I would bind the Enabled properties to Can* (CanWalk, CanJump, etc.) properties of the class, implement INotifyPropertyChanged, and check each potentially affected property when the object's state changes.

The advantage of this method is the Person class and the UI don't need to know anything about each other. Also, implementing INotifyPropertyChanged eliminates superfluous polling of the class's properties after every state change.

If you don't want to use complex databinding, you can still listen for the PropertyChanged events and update the UI manually.

For example:

partial class Person : INotifyPropertyChanged
{
    bool _IsSleeping, _IsSitting;

    public bool IsSleeping 
    { 
        get { return _IsSleeping; } 
        set 
        {
            if(_IsSleeping != value)
            {
                _IsSleeping = value;
                OnIsSleepingChanged();
            }
        }
    }

    public bool IsSitting 
    { 
        get { return _IsSitting; } 
        set 
        {
            if(_IsSitting != value)
            {
                _IsSitting = value;
                OnIsSittingChanged();
            }
        }
    }

    protected virtual void OnIsSleepingChanged()
    {
        NotifyPropertyChanged("IsSleeping");
        CheckCanJumpChanged();
    }

    protected virtual void OnIsSittingChanged()
    {
        NotifyPropertyChanged("IsSitting");
        CheckCanJumpChanged();
    }

    bool CanJump_Old;
    public bool CanJump { get { return !(IsSleeping || IsSitting); } }

    void CheckCanJumpChanged()
    {
        if(CanJump != CanJump_Old)
        {
            CanJump_Old = CanJump;
            NotifyPropertyChanged("CanJump");
        }
    }

    //INotifyPropertyChanged helper method
    private void NotifyPropertyChanged(String prop)
    {
        var hand = PropertyChanged;
        if (hand != null)
            hand(this, new PropertyChangedEventArgs(prop));
    }
}
lc
A: 

It'll depend on whether you're using WPF or WinForms.

WPF lets you databind the Enabled property, so you can declaratively say when it should be enabled, and as long as the right property-changed events are firing, it'll just happen.

With WinForms, yes, setting .Enabled is the way to go. The simplest thing is to write one method called e.g. UpdateEnabled() that updates Enabled on all of your controls based on your rules (if jumping, then btnEat should be disabled), then call that method whenever the state changes.

Since not all state changes are in response to GUI events, you probably want a model object that maintains state and fires an event whenever the state changes. Then whenever that event fires, you can call your UpdateEnabled() method to refresh the GUI based on the new state.

If your needs are simple, that's all you'd need to do. If your app gets more complicated, you'd want to look into patterns like Model-View-Presenter -- the Presenter would be the class that knows, based on the current state, which actions are enabled and which are disabled.

Joe White
+1  A: 

The term you are looking for is state machine.

You can take a look at SimpleStateMachine - C# State Machine Library - Boo and Rhino DSL.

Samuel