2010-10-01 18 views
7

Po pierwsze nie jestem szalony, ponieważ używam MVVM w WinForms-) Wiem o wzorze MVP (Model View Presenter) i jego wariantach. Ale kiedy zacząłem ten projekt, miałem zamiar nauczyć się WPF i używać go, ale jestem zmuszony spieszyć programowanie i nie mam czasu na naukę WPF, więc muszę napisać go w WinForm, który dobrze znam.Windows Forms (WinForms) Model widoku ViewModel (MVVM) do DataBind lub nie

Krótko mówiąc, mam aplikację Smart Client zorientowaną na duże dane, która jest bliska ukończenia, mam wykonane wszystkie Modele i ViewModels (Infrastruktura, Domena, Prezentacja zrobiona) Interfejs użytkownika jest również wykonywany, teraz potrzebuję tylko podłączyć interfejs użytkownika do ViewModels. Najpierw zacząłem podłączanie go przy użyciu standardowego sposobu WinForm (BindingSources i proste wiązanie danych), ale gdy zrobiłem 30-50% wiązania, okazało się, że mój program działa bardzo wolno, mam jak dotąd 100-150 powiązanych właściwości łącznie, 30 z nich są to powiązania domeny głównej (root root) z edycją EditForm. Tak więc zbieranie danych nie działa dobrze w tej sytuacji, wiele niepotrzebnych aktualizacji, kaskadowe aktualizacje całego widoku, gdy coś się zmienia, niejasne zachowanie i inne brzydkie rzeczy. Pachnie jak bardzo niewiarygodny kod, na którym mam niewielką kontrolę. Zacząłem więc przepisywać okablowanie jako czysty, czysty kod WinForms (subskrybując zdarzenia PropertyChange i ListChanged i ustawiając właściwość ViewModels na własną rękę z interfejsu użytkownika). Dużo kodu do napisania, ale działa znacznie szybciej, mam pełną kontrolę nad tym i jest dużo bardziej niezawodny. Więc jakie są twoje przemyślenia na temat tych gości? Ktoś miał takie doświadczenie? Jaki jest twój werdykt w sprawie "Do DataBind czy nie"?

+1

zobaczyć również http://stackoverflow.com/questions/654722/implementing-mvc-with-windows-forms/682216#682216 –

Odpowiedz

1

Użycie wiązania danych w WinForm jest naprawdę bolesne i subskrybowanie zdarzeń INotifyPropertyChanged i ręczne wykonywanie operacji jest przesadzone. Naprawdę lubię MVVM nawet na WinForms, ponieważ jest to świetna testowalność i łatwość obsługi, ale nie za cenę 3X razy więcej kodu do napisania. Więc dla nowego kodu używam teraz połączonego View + ViewModel.

+0

Kiedy mówisz Połączony widok + ViewModel, masz na myśli, że umieszczasz swoje właściwości w kodzie formularza, a następnie używasz tego jako źródła danych obiektu? Myślałem o zrobieniu tego. –

+0

Twoja propgrama była powolna, ponieważ 'BndingSource' zaktualizował wszystkie właściwości VIewModel, jeśli jakiś był domyślnie zmieniony w widoku. Użyj 'DataSourceUpdateMode.Never' na DataBinding w Zwiastuny. I "NotifyPropertyChanged" na właściwościach ViewModel, a następnie kontroluj Databinding – Fabio

6

Być może zechcesz rzucić okiem na Truss. Zapewnia menedżera wiązania w stylu WPF, który działa na POCO. To sprawia, że ​​korzystanie z MVVM z Windows Forms jest o wiele bardziej efektywne.

+0

Bardzo ciekawy, to prawie rozwiązanie, które sobie stworzyłem, napisałem agnostyczny menadżer małych pakietów danych samm z pewnymi elementami refleksyjnymi, ale działa tylko na obiektach INotifyPropertyChanged, więc musiałem podklasować kontrolki WinForm i przesłonić właściwości, których potrzebowałem, zamierzałem wykonać pewne AOP Wstrzykiwanie kodu stylu w ustawieniach właściwości przy użyciu Spring Framework, ale nie udało mi się w tym czasie za mało, umiejętności. Czy używają jakiegoś rodzaju wstrzykiwania kodu w ustawieniach? –

+0

Nie - działają bezpośrednio na POCO, które implementują INPC. Jest całkiem sprytny. –

+0

Fajna, popatrzyłem na ich SRC, to samo zrobiłem, moje i ich źródła są całkiem blisko, a użycie jest takie samo, i myślę, że trudno to zaimplementować w inny sposób :-) Ale jak w moim przypadku to wiązanie działa tylko na obiektach INPC , aby powiązać go na przykład z ComboBox.SelectedItem Będę musiał wykonać MyCombobox: INPC {object SelectedItem {set {base.SelectedItem = value; OnpropertyChanged} i niestety nawet w ten sposób nie działa dobrze, wiele zdarzeń związanych z ogniem zdarzeń \ propety ustawia błędy w kontrolkach WinForms, będę musiał je przepisać (ja też to wypróbowałem, dużo pracy, zrobiłem kilka.) –

1

Inną możliwością jest użycie odziedziczonego komponentu BindingSource do wiązania danych w WinForm. Na przykład: http://ingebrigtsen.info/2010/08/31/mvvm-in-windows-forms/. Działa płynnie nawet w środowisku NET CF.

Mam zmodyfikowany realizację osiągnąć dwa cele:

  • łatwym support wiązania z danymi dla moich ViewModels przez WinForms autora
  • obsługę wielowątkowości z Control.Invoke ponieważ domyślna BindingSource nie obsługuje. Teraz reaguje na zdarzenia PropertyChanged z wątku tła.

Oto mój prosty klasa ViewModelBindingSource:

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); 
     } 
    } 
Powiązane problemy