7

First I'm not mad, because I use MVVM in WinForms-) I know about MVP (Model View Presenter) pattern and its variants. When I started this project I was going to learn WPF and use it, but I'm forced to rush program development, and have no time to learn WPF, so I have to write it in WinForms which I know well.

So in short I have a large data oriented smart client application, which is close to finish, I have all Models and ViewModels done (Infrastructure, Domain, Presentation done) UI is done too, now I only need to wire UI to ViewModels.

First I started wiring it using the standard winforms way (BindingSources, and simple databinding) but when I did 30-50% of binding I found out that my program works very slow, I have like 100-150 bound properties total so far, 30 of them are domain root entity (aggregate root) bindings to its EditForm. So databinding doesn't work well in this situation, lots of unnecessary updates, cascade updates of entire view when something small changes, unclear behavior, and other ugly stuff. It smells like very unreliable code, on which I have little control.

So I began to rewrite wiring as pure clean WinForms code (subscribing to PropertyChange and ListChanged events, and setting ViewModels property on my own from UI). Lot's of code to write but it works much faster, I have full control on this, and it feels much more reliable.

So what's your thoughts on this guys? Anyone had such experience? What's your verdict on "To DataBind or Not"?

eddie
  • 1,252
  • 3
  • 15
  • 20
Alex Burtsev
  • 12,418
  • 8
  • 60
  • 87

3 Answers3

6

You might want to take a look at Truss. It provides a WPF-style binding manager that works on POCOs. It makes using MVVM with Windows Forms much more effective.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Very interesting, it's almost the solution i made for myself, i have wrote UI agnostic small databinder manager myselfm with some reflection stuff but it works only on INotifyPropertyChanged objects so i had to subclass WinForms controls and override the properties i need, i was going to make some AOP style code injection in property setters using Spring Framework, but i failed in this not enough time,skill. Do they use some kind of code injection in setters? – Alex Burtsev Oct 01 '10 at 17:45
  • No - they work directly on POCO's that implement INPC. It's pretty slick. – Reed Copsey Oct 01 '10 at 17:51
  • Nice one, looked at their SRC, same thing i did, my and their sources are pretty close, and usage is same, i guess hard to implement this other way :-) But as in my case this binding works just on INPC objects, so to bind it to for example ComboBox.SelectedItem I will have to do MyCombobox : INPC {object SelectedItem {set {base.SelectedItem = value; OnpropertyChanged} and unfortunately even this way it doesn't work well, lots of event fire stuff\propety set bugs in WinForms controls, i will have to rewrite them (i tried this too, lots of work, did some.) – Alex Burtsev Oct 01 '10 at 18:25
  • It would be much nicer to have some interception stuff in property SET method like it is in Nhibernate for example. – Alex Burtsev Oct 01 '10 at 18:26
  • Interesting thing i found "remade" WinForms controls in http://updatecontrols.codeplex.com/ project, they subclass WinForms controls and add OnGet OnSet handlers in control properties, pity they don't just add OnPropertyChanged stuff there. I could rewrite their subclassed controls with INPC to use with Truss. – Alex Burtsev Oct 07 '10 at 07:27
  • Does anyone here know good learning resources on all those patterns? I feel like I'm also gonna have to make some solution on this. This is a question I asked recently by the way: http://stackoverflow.com/questions/26132035/custom-logic-in-windows-forms-data-binding – Eduardo Wada Oct 02 '14 at 21:15
  • @EduardoWada Use WPF if you want MVVM style bindings - it's MUCH nicer than windows forms would ever be... – Reed Copsey Oct 02 '14 at 21:26
  • I have windows forms code already, so I'm more into a windows forms refactor or simply a new style to develop new controls, even if its not as nice as WPF, but I would like some architecture where test automation was even possible – Eduardo Wada Oct 02 '14 at 21:33
  • @EduardoWada In general, using WPF, and embedding in ElementHost will work better. WinForms just doesn't work with MVVM... – Reed Copsey Oct 02 '14 at 21:43
2

Another possibility is to use a inherited BindingSource component for data-binding in WinForms. For example: http://ingebrigtsen.info/2010/08/31/mvvm-in-windows-forms/. It works smoothly even in NET CF Environments.

I have modified the implementation to achieve two goals:

  • an easy databinding support for my ViewModels through WinForms designer
  • multithreading support with control.Invoke because the default BindingSource doesn't support it. Now it reacts to PropertyChanged events from a background thread.

Here is my simple ViewModelBindingSource class:

public class ViewModelBindingSource : BindingSource
{
    private readonly Control _control = new Control();
    private object _viewModel;
    private Type _viewModelType;

    public ViewModelBindingSource()
    {
    }

    public ViewModelBindingSource(IContainer container)
        : base(container)
    {
    }

    public ViewModelBindingSource(object dataSource, string dataMember)
        : base(dataSource, dataMember)
    {
    }

    public object ViewModel
    {
        get { return _viewModel; }
        set { _viewModel = value; }
    }

    public Type ViewModelType 
    { 
        get { return _viewModelType; }
        set
        {
            if (value != null)
            {
                // save the type of our viewmodel
                _viewModelType = value;
                // create an instance of our viewmodel - so we don't need codebehind
                _viewModel = Activator.CreateInstance(_viewModelType);
                // add the viewmodel instance to the internal IList collection of the bindingsource
                Add(_viewModel);
                // move to the first element
                MoveFirst();
                // set the datasource of the binding source to the first element
                // this is necessary for data binding of all windows forms controls
                DataSource = this[0];
            }
        }
    }

    /// <summary>
    /// Pass the call to the main thread for windows forms
    /// This is needed for multithreading support.
    /// </summary>
    /// <param name="e"></param>
    protected override void OnListChanged(ListChangedEventArgs e)
    {
        if (_control != null && _control.InvokeRequired)
            _control.Invoke(new Action<ListChangedEventArgs>(OnListChanged), e);
        else
        {
            base.OnListChanged(e);
        }
    }
Sven
  • 2,345
  • 2
  • 21
  • 43
1

Using data-binding in WinForms is really painful, and subscribing to INotifyPropertyChanged events and doing things manually is overkill. I really like MVVM even on WinForms for it's great testability and maintainability but not at a price of 3X times more code to write. So for new code I use now combined View+ViewModel.

Alex Burtsev
  • 12,418
  • 8
  • 60
  • 87
  • When you say combined View+ViewModel do you mean that you put your properties in the form code behind and then use that as your object data source? I was thinking of doing this. – The Muffin Man Feb 05 '15 at 00:09
  • Your propgram was slow because `BndingSource` update all VIewModel's properties if some one was changed in the view by default. Use `DataSourceUpdateMode.Never` on the DataBinding in the VIew. And `NotifyPropertyChanged` on the ViewModel's properties, then have control of Databinding – Fabio Nov 16 '15 at 03:17