4

I am running into an issue that I have found on some similar post, however, they are not quite the same and I am not quite sure how to apply it to my scenario. They may or may not be the same as my case. So, I am posting my own question here hopefully, I will get an answer to my specific scenario.

Basically, I have a window form with a bunch of controls. I would like to have the ability to bind their Enabled property to a Boolean variable that I set so that they can be enable or disable to my discretion.

public partial class MyUI : Form
{
    private int _myID;
    public  int  myID 
    {
        get
        {
            return _myID;;
        }
        set
        {
            if (value!=null)
            {
                _bEnable = true;
            }
        }
    }
    private bool _bEnable = false;
    public bool isEnabled
    {
        get { return _bEnable; }
        set { _bEnable = value; }
    }

    public myUI()
    {
        InitializeComponent();
    }

public void EnableControls()
{
   if (_bEnable)
   {
    ctl1.Enabled = true;
    ctl2.Enabled = true;
            ......
    ctl5.Enabled = true;
   }
       else
   {
    ctl1.Enabled = false;
    ctl2.Enabled = false;
            ......
    ctl5.Enabled = false;
       }
}
}

}

The method EnableControls above would do what I need but it may not be the best approach. I prefer to have ctrl1..5 be bound to my variable _bEnable. The variable will change depending on one field users enter, if the value in the field exists in the database, then other controls will be enabled for user to update otherwise they will be disabled.

I have found a very similar question here but the data is bound to the text field. How do I get rid of the EnableControls method and bind the value of _bEnabled to the "Enabled" property in each control?

Community
  • 1
  • 1
user1205746
  • 3,110
  • 11
  • 44
  • 73
  • 2
    You are "wrestling" with the state of your application. This is a common problem in designing applications. Have a look a some well known design patterns, like MVP, MVC or MVVM. – JvdBerg Dec 26 '13 at 21:38

2 Answers2

11

Go look into the MVVM (Model - View - ViewModel) pattern, specifically its implementation within Windows Forms. Its much easier to apply it to a WPF/Silverlight application, but you can still use it with Windows Forms without too much trouble.

To solve your problem directly, you will need to do 2 things:

  1. Create some class that will hold your internal state (i.e. whether or not the buttons are enabled). This class must implement INotifyPropertyChanged. This will be your View Model in the MVVM pattern.
  2. Bind an instance of the class from 1.) above to your Form. Your form is the View in the MVVM pattern.

After you have done 1 and 2 above, you can then change the state of your class (i.e. change a property representing whether a button is enabled from true to false) and the Form will be updated automatically to show this change.

The code below should be enough to get the concept working. You will need to extend it obviously, but it should be enough to get you started.

View Model

public class ViewModel : INotifyPropertyChanged
{
    private bool _isDoStuffButtonEnabled;
    public bool IsDoStuffButtonEnabled
    {
        get
        {
            return _isDoStuffButtonEnabled;
        }
        set
        {
            if (_isDoStuffButtonEnabled == value) return;
            _isDoStuffButtonEnabled = value;
            RaisePropertyChanged("IsDoStuffButtonEnabled");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

View

public class View : Form
{
    public Button DoStuffButton { get; set; }

    public void Bind(ViewModel vm)
    {
        DoStuffButton.DataBindings.Add("Enabled", vm, "IsDoStuffButtonEnabled");
    }
}

Usage

public class Startup
{
    public ViewModel ViewModel { get; set; }
    public View View { get; set; }

    public void Startup()
    {
        ViewModel = new ViewModel();
        View = new View();

        View.Bind(ViewModel);

        View.Show();

        ViewModel.IsDoStuffButtonEnabled = true;

        // Button becomes enabled on form.

        // ... other stuff here.
    }
}
Todd Bowles
  • 1,554
  • 15
  • 24
  • That's elegant and is what I am missing. I will dig more in MVVC to learn more but your answer already got me going... :) thank you so much! – user1205746 Dec 26 '13 at 22:04
  • I guess I need to do more reading about MVVM which is new to me. I do not have a chance/luxury to do that yet but I have a quick follow up question regarding your explanation, which I think "I understand". So, if I understand you correctly, usage/startup should be in a different class called Model and is it safe to say that, from your explanation above,the View does not "talk" directly to the ViewModel but will only receive instruction from it?Now, how does View communicate changes back to the ViewModel or Model if there is change from the view? Like user types something in the textbox? – user1205746 Dec 27 '13 at 04:24
  • 2
    Depending on which property of the Windows Forms control you are binding to, two way binding might be possible. Two way binding being that changes on either end are communicated (like a text box value being entered back into the property of the View Model it is bound to). Have you read [MVVM Pattern For Windows Forms](http://www.codeproject.com/Articles/364485/MVVM-Model-View-ViewModel-Patte)? Its a bit of a paradigm shift from standard Windows Forms development, but its much much better for a variety of reasons. – Todd Bowles Dec 27 '13 at 06:15
  • Thank you for the link. I will take a look at it. It look like the document-view pattern from C++. This is nice. – user1205746 Dec 27 '13 at 13:59
0

Maybe you can try this approach: in your isEnabled property's setter method, add an if statement:

if(_bEnable) EnableControls();
else DisableControls();

And if your control names are ctl1,ctl2... etc. you can try this:

EnableControls()
{
   for(int i=1; i<6;i++)
   {
      string controlName = "ctl" + i;
      this.Controls[controlName].Enabled = true;
   }
}

And apply the same logic in DisableControls

If you have more controls in future this could be more elegant.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184