开发者

Windows Forms (WinForms) Model View ViewModel pattern (MVVM) to DataBind or not

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开发者_如何学JAVA 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"?


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.


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.


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜