在各种不同条件下,在多个控件中启用/禁用某些控件的最佳方法是什么?

时间:2022-05-16 15:54:08

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?

我是专业编程的新手,我正在编写C#,但我认为这不完全是C#特有的。无论如何,我想问一下在各种不同条件下启用/禁用多个控件中的某些控件的最佳方法是什么?

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.

让我们说,有一个GUI有一些行,每个行代表一个人。还有一些按钮,代表一些动作,比如“站立,坐,走,跳,吃,看电视,醒来,睡觉”,还有一些条件,比如如果有人坐着他可以吃饭和看电视(即启用那些按钮)但不能跳(禁用它),如果有人站着他不能睡觉........等等。此外,状态更改不仅仅基于按钮单击。就像,他可能会在一段时间后自己醒来,或者说,吃完了。

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?

似乎最天真的方式是编写.Enabled = true / false; n个状态的代码X m按钮次数,并检查每个用户或非用户触发的状态更改。有没有更好/更快/更少错误的方法呢?

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.

还有什么叫这种东西?我不知道用英语写一个合适的术语来描述它,所以我不能自己谷歌....请帮忙。非常感谢你。

3 个解决方案

#1


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

这取决于您使用的是WPF还是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.

WPF允许您对Enabled属性进行数据绑定,因此您可以声明性地说明何时应该启用它,并且只要正确的属性更改事件被触发,它就会发生。

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.

使用WinForms,是的,设置.Enabled是要走的路。最简单的方法是编写一个名为eg的方法。 UpdateEnabled()根据您的规则更新所有控件的Enabled(如果跳转,则应禁用btnEat),然后在状态更改时调用该方法。

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.

由于并非所有状态更改都是对GUI事件的响应,因此您可能需要一个模型对象来维护状态并在状态更改时触发事件。然后,只要该事件触发,您就可以调用UpdateEnabled()方法根据新状态刷新GUI。

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.

如果您的需求很简单,那就是您需要做的一切。如果您的应用程序变得更复杂,您需要查看模型 - 视图 - 演示者 - 模式将是基于当前状态知道哪些操作已启用且哪些已禁用的类。

#2


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.

我将Enabled属性绑定到类的Can *(CanWalk,CanJump等)属性,实现INotifyPropertyChanged,并在对象的状态更改时检查每个可能受影响的属性。

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.

此方法的优点是Person类,UI不需要彼此了解任何内容。此外,实现INotifyPropertyChanged可在每次状态更改后消除对类属性的多余轮询。

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

如果您不想使用复杂的数据绑定,您仍然可以侦听PropertyChanged事件并手动更新UI。

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));
    }
}

#3


The term you are looking for is state machine.

您正在寻找的术语是状态机。

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

你可以看一下SimpleStateMachine - C#状态机库 - Boo和Rhino DSL。

#1


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

这取决于您使用的是WPF还是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.

WPF允许您对Enabled属性进行数据绑定,因此您可以声明性地说明何时应该启用它,并且只要正确的属性更改事件被触发,它就会发生。

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.

使用WinForms,是的,设置.Enabled是要走的路。最简单的方法是编写一个名为eg的方法。 UpdateEnabled()根据您的规则更新所有控件的Enabled(如果跳转,则应禁用btnEat),然后在状态更改时调用该方法。

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.

由于并非所有状态更改都是对GUI事件的响应,因此您可能需要一个模型对象来维护状态并在状态更改时触发事件。然后,只要该事件触发,您就可以调用UpdateEnabled()方法根据新状态刷新GUI。

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.

如果您的需求很简单,那就是您需要做的一切。如果您的应用程序变得更复杂,您需要查看模型 - 视图 - 演示者 - 模式将是基于当前状态知道哪些操作已启用且哪些已禁用的类。

#2


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.

我将Enabled属性绑定到类的Can *(CanWalk,CanJump等)属性,实现INotifyPropertyChanged,并在对象的状态更改时检查每个可能受影响的属性。

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.

此方法的优点是Person类,UI不需要彼此了解任何内容。此外,实现INotifyPropertyChanged可在每次状态更改后消除对类属性的多余轮询。

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

如果您不想使用复杂的数据绑定,您仍然可以侦听PropertyChanged事件并手动更新UI。

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));
    }
}

#3


The term you are looking for is state machine.

您正在寻找的术语是状态机。

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

你可以看一下SimpleStateMachine - C#状态机库 - Boo和Rhino DSL。