Databinding WinForm controls

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
28,048
Reaction score
17,803
Could someone please give me a run down on a better way to do these types of things?

I have built my own utils class in which I use this:

PHP:
public static void FillDropdown(ComboBox cmb, DataSet ds, string displaymember, string valuemember)
    {

        cmb.DataSource = ds.Tables[0];
        cmb.DisplayMember = displaymember;
        cmb.ValueMember = valuemember;

        DataRow dr = ds.Tables[0].NewRow();
        dr[displaymember] = "Select";
        dr[valuemember] = 0;

        ds.Tables[0].Rows.InsertAt(dr, 0);
        cmb.SelectedIndex = 0;
}

PHP:
public void FillEmployeeDropdown()
    {
         Utilities.FillDropdown(cboEmployee, jobsBAL.GetEmployees(), "EmployeeName", "Id");
    }

Secondly: I'm asking this because I have been doing this and it's been pointed out that's it's not a terribly good way of getting data into controls.

PHP:
DataSet ds = jobsBAL.GetJobByJobNo(job.JobNo);

job.JobDate = Convert.ToDateTime(ds.Tables[0].Rows[0]["JobDate"]);

dtDate.Value = job.JobDate;
 
Last edited:
Was actually thinking of creating a thread for this. I will create a detailed reply in the week.

I have used databinding extensively to write a MVVM framework for WinForms... Why Winforms you ask? Because apart from enterprise apps I also do lots of mobile WinCE stuff. Dev for a device is a pain from a debugging perspective. So, all the behaviour is put into the ViewModel so that I can actually run and debug the entire app on the desktop. The mobile app solution simply links those ViewModels, but then simply hooks a WinCE form to the ViewModel for display. So in the end you have no code in for form apart from creating the bindings.
 
Was actually thinking of creating a thread for this. I will create a detailed reply in the week.

I have used databinding extensively to write a MVVM framework for WinForms... Why Winforms you ask? Because apart from enterprise apps I also do lots of mobile WinCE stuff. Dev for a device is a pain from a debugging perspective. So, all the behaviour is put into the ViewModel so that I can actually run and debug the entire app on the desktop. The mobile app solution simply links those ViewModels, but then simply hooks a WinCE form to the ViewModel for display. So in the end you have no code in for form apart from creating the bindings.

Awesome!
 
Ok so here is the first post on databinding. This will be a couple of posts where I discuss databinding and also the separation of concerns regarding form behaviour and presentation at the hand of the MVVM pattern.

The philisophy behind the MVVM pattern is that the (M)odel carries the data being presented, the (V)iew(M)odel controls the (V)iew and controls access to the (M)odel. The (V)iew is purely the presentation of the model and VM state. There are several schools of thought as to how this is supposed to work. Some ppl say that the View should be abstracted by an interface and injected into the VM and the VM controls the View through this interface. However, I don't agree with this. This creates an 'outward' dependency that I don't like. My opinion is that the View must be a passive observer (presenter) of the ViewModel and Model wrt presentation of info and then 'push' user interaction to the VM through loosely coupled mechanisms.

These posts will loosely follow the implementation I did for my own MVVM framework for Winforms. If you doubt the benefit of this pattern, I hope that these posts will change your mind.
In the code I am using 'older' C# syntax as this is supported way back to Compact Framework 1. I use the MVVM framework on WinCE devices as well.

The source is here: https://dl.dropboxusercontent.com/u/47608139/MyBB/WinformsDataBinding1.zip

To define some terms:
Behaviour is how the form/view behaves as the user interacts with it. Behaviour forms part of the User Experience (UX).
Presentation is how the data and interactive controls are visually presented. The Presentation also forms part of the UX.

Ideally the VM should be completely agnostic of what the presentation looks like. This will become evident in this post.

Databinding is a very powerful mechanism. Not only can you use it to bind user entry, but also the control the behaviour of controls and presentation on the form. Databinding works by means of the INotifyPropertyChanged interface. You can databind to an object that implements this interface. For the purposes of this demo, I have created a base class called ObservableObject that implements this interface.

Code:
using System.ComponentModel;

namespace WinformsDataBinding1
{
  public class ObservableObject: 
    INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler == null)
        return;

      handler(this,new PropertyChangedEventArgs(propertyName));
    }
  }
}

Take note of the above event dispatcher. This is how you have to to it and not as below

Code:
      if (PropertyChanged == null)
        return;

      PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
The above can create race conditions in multi-threaded environments. But that is a topic in itself.

We will derive our ViewModel from the ObservableObject purely to reuse the event and event dispatcher.


We define our ViewModel as

Code:
using System;

namespace WinformsDataBinding1
{
  public class ViewModel:
    ObservableObject
  {
    public DateTime TheDay
    {
      get { return theDay; }
      set
      {
        if (theDay == value)
          return;

        theDay = value;

        OnPropertyChanged("TheDay");

        TheDayAfter = TheDay.AddDays(1);
        TheDayAfterIsEnabled = TheDayAfter.Year < 2018;

      }
    }
    public DateTime TheDayAfter
    {
      get { return theDayAfter; }
      private set
      {
        if (theDayAfter == value)
          return;

        theDayAfter = value;

        OnPropertyChanged("TheDayAfter");
      }
    }
    public bool TheDayAfterIsEnabled
    {
      get { return theDayAfterIsEnabled; }
      private set
      {
        if (theDayAfterIsEnabled == value)
          return;

        theDayAfterIsEnabled = value;

        OnPropertyChanged("TheDayAfterIsEnabled");
      }
    }
    public bool TheDayAfterIsThisYear
    {
      get { return TheDayAfter.Year == DateTime.Today.Year; }
    }
    public bool TheDayAfterIsNextYear
    {
      get { return TheDayAfter.Year == DateTime.Today.Year + 1; }
    }

    public string Task
    {
      get { return task; }
      set
      {
        if (task == value)
          return;

        task = value;

        OnPropertyChanged("Task");
      }
    }
    public bool CanDoTheTask
    {
      get { return string.IsNullOrEmpty(task) == false; }
    }
    public void InitialView()
    {
      TheDay = DateTime.Today;
    }

    private DateTime theDay;
    private DateTime theDayAfter;
    private bool theDayAfterIsEnabled = true;
  }
}

So the 'UX' behind the form is as follows:
- The user can select a date in edtTheDay.
- edtTheDayAfter displays the date of the next day
- edtTheDayAfter is enabled if the day after is < 2018
- lblNextYear is visibile only if the selected date is in the following year
- btnHappy is enabled only if the selected date is in the following year
- pnlThisYear is green if the selected date is in this year and red otherwise.
- btnDoIt is active only when edtTask is not empty

So this seems like a strange UX but it illustrates the power of databinding and how easy this can be achieved with very little (and simple) code.

This ViewModel has the following properties:
TheDay is a property that is user-editable
Code:
   public DateTime TheDay
    {
      get { return theDay; }
      set
      {
        if (theDay == value)
          return;

        theDay = value;

        OnPropertyChanged("TheDay");

        TheDayAfter = TheDay.AddDays(1);
        TheDayAfterIsEnabled = TheDayAfter.Year < 2018;

      }
    }
This is why it has a public getter and setter. The getter is executed when databinding needs the field value for display in the control. The setter is executed when the user changes the value in the control (more about this later). Take note of the setter pattern. Firstly it checks if the value has changed. If not, return. When the new value is diff from the current, update it and raise the event to signal change.

Once this is done, the ViewModel can update other values in the Model as well e.g. TheDayAfter.

TheDayAfter property is never set by the user and its setter is private. It is only set by the VM based on the desired rules.

Code:
    public DateTime TheDayAfter
    {
      get { return theDayAfter; }
      private set
      {
        if (theDayAfter == value)
          return;

        theDayAfter = value;

        OnPropertyChanged("TheDayAfter");
      }
    }
The setter for TheDayAfter also checks for changes and raises the change event. This is why the setter for TheDay sets the property (executes setter) instead of setting the backing field.

TheDayAfterIsEnabled is also set based on TheDay and the UX rules we have set.

The above 2 properties illustrate one approach to modifying the Model. When these properties are set, they raise the change event.

The next 2 properties follow a different approach. Their values are purely based on the value of TheDay. This means that to display these values,, databinding only needs the getters. The getters return the 'calculated' value of the property based on TheDay.

Code:
    public bool TheDayAfterIsThisYear
    {
      get { return TheDayAfter.Year == DateTime.Today.Year; }
    }
    public bool TheDayAfterIsNextYear
    {
      get { return TheDayAfter.Year == DateTime.Today.Year + 1; }
    }

The difference in approach is actually quite interesting. In fact all the readonly properties could have followed either the first or the second approach. What I have found is that when you have controls bound to the VM propeties, whenever one property changed event is raised, ALL the bound properties are read. This removes the need to raise an event for change in each read-only property. However I have read somewhere that this was bound to change in that only the property that changed would be read. But somehow that does not seem to be the case yet. By implication, all readonly/dependent properties only then need getters (approach 2). But make sure that your getters are lightweight as they are executed many times. Use lazy loading etc if needed. So when MS implements the reading of only the property that changed, then you need to use approach 1. In C#5 there are mechanisms that mark properties dependent on others that makes databinding a bit more intelligent.

Code:
    public string Task
    {
      get { return task; }
      set
      {
        if (task == value)
          return;

        task = value;

        OnPropertyChanged("Task");
      }
    }

    public bool CanDoTheTask
    {
      get { return string.IsNullOrEmpty(task) == false; }
    }
The CanDoTheTask property is only true when the Task user-editable property is not empty. That is al you need to do!!!

So now we have implemented all our properties that will drive behaviour and present the Model to the View. You can see that the VM knows nothing about the View/presentation. In fact, it does not even import the System.Windows.Forms namespace.


Fuuuuuuuuu... the site threw away huge edits.....!!!!
 
Last edited:
Lets look at the View/Form.

We use property injection to attach the form to the ViewModel, because we need the default ctor to make the designer work... We could have another ctor and use DI, but the CreateBindings method is virtual and the compiler gives a warning. The ViewModel property setter executes the CreateBindings method and that is where the magic happens.

Code:
    protected virtual void CreateBindings()
    {
      edtTheDay.DataBindings.Add("Value", ViewModel, "TheDay", true, DataSourceUpdateMode.OnPropertyChanged);

      edtTheDayAfter.DataBindings.Add("Value", ViewModel, "TheDayAfter", true, DataSourceUpdateMode.Never);
      edtTheDayAfter.DataBindings.Add("Enabled", ViewModel, "TheDayAfterIsEnabled", true, DataSourceUpdateMode.Never);
      lblNextYear.DataBindings.Add("Visible", ViewModel, "TheDayAfterIsNextYear", true, DataSourceUpdateMode.Never);
      btnHappy.DataBindings.Add("Enabled", ViewModel, "TheDayAfterIsNextYear", true, DataSourceUpdateMode.Never);

      DataBindings.Add("TheDayAfterIsThisYear", ViewModel, "TheDayAfterIsThisYear", true, DataSourceUpdateMode.Never);

      edtTask.DataBindings.Add("Text", ViewModel, "Task", true, DataSourceUpdateMode.OnPropertyChanged);
      btnDoIt.DataBindings.Add("Enabled", ViewModel, "CanDoTheTask", true, DataSourceUpdateMode.Never);

    }

The statement below tell the databinding mechanism the following:
- we are binding to the Value property of the edtTheDay control
- we are binding the above to the TheDay property on the ViewModel as the datasource.
- the true forces type conversion between the control property and data source property data types. In thiscase they are the same but can differ e.g. string & DateTime.
- DataSourceUpdateMode.OnPropertyChanged tell databinding to propagate the Value property value of the control to the TheDay property on the ViewModel every time the control value changes. This executes the setter onthe VM property. If you use DataSourceUpdateMode.OnValidation, the value only propagates when the control value is validated. Usually when the focus leaves the control.
Code:
      edtTheDay.DataBindings.Add("Value", ViewModel, "TheDay", true, DataSourceUpdateMode.OnPropertyChanged);

The read-only properties are bound in similar way except for DataSourceUpdateMode.Never. This indicates that the control value will never propagate to the datasource (VM). Note that we are binding to Enabled and Visible properties as well. This therefore dynamically controls whether the control is enabled or visible.
Code:
      edtTheDayAfter.DataBindings.Add("Value", ViewModel, "TheDayAfter", true, DataSourceUpdateMode.Never);
      edtTheDayAfter.DataBindings.Add("Enabled", ViewModel, "TheDayAfterIsEnabled", true, DataSourceUpdateMode.Never);
      lblNextYear.DataBindings.Add("Visible", ViewModel, "TheDayAfterIsNextYear", true, DataSourceUpdateMode.Never);
      btnHappy.DataBindings.Add("Enabled", ViewModel, "TheDayAfterIsNextYear", true, DataSourceUpdateMode.Never);

This binding is interesting.
Code:
     DataBindings.Add("TheDayAfterIsThisYear", ViewModel, "TheDayAfterIsThisYear", true, DataSourceUpdateMode.Never);

We want the colour of the panel to change based on TheDay. We could of course added a Colour property to the VM. However, the colour is a presentation concern that the VM should know nothing about. It does not need to know how that particular condition is indicated. That is the View's responsibility. So to solve this,we create a property on the form that represents the condition. The getter return value is not important as it does not get used anywhere. The setter makes the necessary presentation changes to the controls it owns to reflect the condition.
Code:
    public bool TheDayAfterIsThisYear
    {
      get { return false; }
      set { pnlThisYear.BackColor = value ? Color.GreenYellow : Color.Red; }
    }


The edtTask.Text property binds to the ViewModel.Task property and the btnDoIt.Enabled property binds to the ViewModel.CanDoTheTask property that indicates state. This is all you have to do to achieve this behaviour!! No event handers needed....!
Code:
      edtTask.DataBindings.Add("Text", ViewModel, "Task", true, DataSourceUpdateMode.OnPropertyChanged);
      btnDoIt.DataBindings.Add("Enabled", ViewModel, "CanDoTheTask", true, DataSourceUpdateMode.Never);


So this is it for now. Play with the app and experience how much interaction and behaviour was achieved with very little code. No need to manually update control states throughout the form and event handlers (note that there are none).

Feel free to comment/ask ...

[EDIT]

Forgot to show how it is wired together... Later we will move this wiring up to builder classes and CompositionRoot class...

Code:
      frmView frm = new frmView();
      frm.ViewModel = new ViewModel();
      frm.ViewModel.InitialView();

      Application.Run(frm);
 
Last edited:
This is extensive. Many thanks spacerat, I'm going to need a lot of coffee for this. Well, from the beginning. I've got several days free now including all of next week. Think I'm going to need it for this but this stuff is really important to get to grips with. I'll post any questions I've got here as I'm going along. I've been hearing about MVVM and WPF, I've know it was coming eventually. Many, many thanks!
 
Lets look at the View/Form.

We use property injection to attach the form to the ViewModel, because we need the default ctor to make the designer work... We could have another ctor and use DI, but the CreateBindings method is virtual and the compiler gives a warning. The ViewModel property setter executes the CreateBindings method and that is where the magic happens.

/snip
[/CODE]

I have actually abandoned everyone else for now and have come back to this. I have one question, the UI is decoupled with this example yes?
 
I dont use MVVM because there isnt really a need to in my company, so here is how I do it.

private void PopCombos()
{
obj.LoadCMBLIST("parameters"); //sql - select * from table where etc etc
if (obj.RowCount > 0) //doodads sql obj
{
cmbFac.DropDownStyle = ComboBoxStyle.DropDownList;
//cmbFac.AutoCompleteMode = AutoCompleteMode.Suggest;
cmbFac.DataSource = obj.DefaultView;
cmbFac.ValueMember = "ColVal";
cmbFac.DisplayMember = "ColDesc";
}
}
 
I have actually abandoned everyone else for now and have come back to this. I have one question, the UI is decoupled with this example yes?
Yes completely decoupled in the sense that the form and its controls are only linked to the VM through databinding. There is no behaviour in the form either. All behaaviour sits in the VM. TBH I use MVVM for prettty much any app even tiny small ones as well as WindowsMobile apps.
 
The button click I can't quite wrap my head around. One you click it the first thing to fire off in the viewmodel is Task, even though there is nothing in the button's binding to suggest it should do so. unless I'm missing something which is likely.

Another thing, when I populate the text field edtTsk, towards the end of the codes cycle in the view model, it then suddenly jumps to CanDoTheTask like out of nowhere and enables the button. Quite mystifying!
 
Last edited:
The button click I can't quite wrap my head around. One you click it the first thing to fire off in the viewmodel is Task, even though there is nothing in the button's binding to suggest it should do so. unless I'm missing something which is likely.

Another thing, when I populate the text field edtTsk, towards the end of the codes cycle in the view model, it then suddenly jumps to CanDoTheTask like out of nowhere and enables the button. Quite mystifying!
That's the magic that happens behind the scenes. ;) It took me a while to write this so that a control click event propagates to the ICommand. Also as you toggle the command.CanExecute, the button automatically changes state. Therefore the button states are also controlled by the VM. I wll need to look at the example code again to explain. My goal when writing the MVVM framework was to make the form and controls as independent from the VM as possible and to make the VM and form completely decoupled.
 
That's the magic that happens behind the scenes. ;) It took me a while to write this so that a control click event propagates to the ICommand. Also as you toggle the command.CanExecute, the button automatically changes state. Therefore the button states are also controlled by the VM. I wll need to look at the example code again to explain. My goal when writing the MVVM framework was to make the form and controls as independent from the VM as possible and to make the VM and form completely decoupled.

That is my goal at the moment. I have managed to achieve decoupling on my previous application (welcome to have a look at the project if you want) but now taking it a step further.

There is certainly some magic going on in there hehe. At the moment I can pass text between textboxes, now moved on to a combo box and then datagrid etc.

I really do like this way of keeping the functionality and UI separate, so going to put in the effort on this.
 
Last edited:
An alternative solution to the challenges described here is turning the control stylng and population into a composable templating solution, and for the management / decoupling of UI and Model to consider managing state with either or a combination of the reducer pattern, state monad, and observers.
 
Last edited:
That is my goal at the moment. I have managed to achieve decoupling on my previous application (welcome to have a look at the project if you want) but now taking it a step further.

There is certainly some magic going on in there hehe. At the moment I can pass text between textboxes, now moved on to a combo box and then datagrid etc.

I really do like this way of keeping the functionality and UI separate, so going to put in the effort on this.

I had another look at my example above. I see that I have not included the binding of control events in there. The example merely showed the mechanisms to bind the model in the VM to the form controls to achieve decoupling and separation of concerns. The binding of control events to the VM is not DataBinding per-se in the WinForms DataBinding context but it is a great way to further decouple the Form from the VM. It means you don't have to have:
Code:
private void button_Click(object sender,EventArgs e)
{
  viewModel.SomeMethod();
}

you simply bind the button to a Command in the VM in the CreateBindings
Code:
  mvvmContext.CreateBinding(new ControlClickBinding(button,viewModel.SomeCommand));

The magic you are observing is that built in to the DataBinding mechanisms. When you change a property value (model value) in the VM, the PropertyChanged event is fired. This triggers the WinForms DataBinding mechanism to, for each binding you set up in the form, read the associated (bound) value from the VM. Even if that value did not change. This is what you are seeing wrt property getters being executed 'magically'. So a VM (model) property change causes a refresh of all controls that are bound to the VM. So be careful to not make the VM property getter an expensive operation.[/CODE]
 
That's a good example... a very simple abstraction with so much potential.

I also posted a simple example of building this pattern from scratch and how to use it to decouple state, view and controller in a simple game (the code's in Swift but it can easily be translated) : https://mybroadband.co.za/forum/threads/functional-thread-5.966319/

The alternatives to this redux style pattern is of course Elm's approach and the more abstract concept of the state monad.
 
Back, was in Mpumulanga for a couple of days.
 
Top
Sign up to the MyBroadband newsletter
X