ComboBox w MVP

0

Witam,
Zakręciłem się przy próbie umieszczenia comboBox'a w szablonie MVP.
Umieszczam comboBox ma formie. Forma wystawia interface na podstawie którego klasa presenter buduje obiekt. Poprzez interface jest wystawiany obiekt(model) z formy który powinien pobrać/oddać dane. Nie może on jednak (chyba) zawierać obiektu comboBox tylko ewentualnie dane które powinien otrzymać. Teraz nie wiem czy zbudować szablonowy obiekt na wzór comboBoxa który zawiera dataSource, DisplayMember, ValueMember i SelectedValue. Podać mu dane w Modelu i poprzez presentera przekazać do właściwego comboBoxa? Chociaż też nie bo interface nie wystawia comboBox'a. Help :-)
Chyba, że mogę wystawić comboBox'a poprzez interface do presentera - wtedy prościzna ;-)

W takim przypadku byłoby tak:

Model

 
public class RaportowanieModel : EntityBase
    {
        public int miesiac { get; set; }
        public int rok { get; set; }
        public ComboBox rokComboBox = new ComboBox();
        public ComboBox miesiacComboBox = new ComboBox();
        public DataTable raportyWyborDanychDT { get; set; }
        public DataRow raportyWyborDanychCurrentDR { get; set; }
    }

Presenter

 public void Initialize(IRaportowanie view)
        {
            zapytanieDataGrid.utworzSELECT("RaportyWyborDanychCalosc_v",
                new List<string> { "*" }, new string[] { "month(dataWaluty)=? AND year(dataWaluty)=?", "dataWaluty DESC" });
            zapytanieDataGrid.dodajParametr("@P1", "int");
            zapytanieDataGrid.dodajParametr("@P2", "int");
            view.raportowanieModel = new Model.RaportowanieModel();
        }

        public void load(IRaportowanie view)
        {
            Pomocne.ComboBoxUstaw.rok(view.raportowanieModel.rokComboBox);
            Pomocne.ComboBoxUstaw.miesiac(view.raportowanieModel.miesiacComboBox);
        }

View

 
 public Raportowanie()
        {
            InitializeComponent();
            presenter.Initialize(this);
            raportowanieModel.rokComboBox = this.rokComboBox;
            raportowanieModel.miesiacComboBox = this.miesiacComboBox;
        }


        private void Raportowanie_Load(object sender, EventArgs e)
        {
            presenter.load(this);
            presenter.daneDoDataGrid(this);
        }


        #region IRaportowanie

        public RaportowanieModel raportowanieModel
        {
            get { return this.raportowanieModelBindingSource.Current as RaportowanieModel; }
            set { this.raportowanieModelBindingSource.DataSource = value; }
        }

Model -> oczekuje obiektów comboBox
Presenter -> przy wywołaniu Initializera powołuje do życia model
View -> konstruktor przekazuje referencję ze swoich comboBox'ow do tych z modelu
View -> Load pobiera poprzez prezentera dane do comboBox

działa ale mi się nie podoba :/

Pozdrawiam,
Zoritt

1

Model ani Presenter nie powinny nic wiedzieć o istnieniu czegoś takiego jak ComboBox. To jest szczegół implementacji znajdujący się w Widoku.
Interfejs IRaportowanie powinien zawierać właściwości, które ustawiasz w Prezenterze, zaś Widok powinien je zaimplementować i ustawić wartości w ComboBoxie. W szczególności powinna być to jakaś lista obiektów, która potem zostanie zbindowana z DataSource oraz wybrany obiekt, który zostanie zbindowany z SelectedValue. Natomiast DisplayMember i ValueMember ustawiłbym po prostu w designerze, chyba nie będą się zmieniały, prawda?

0

OK. Po poprawkach.
O niebo lepiej ale jeszcze wydaje mi się, że mam za bardzo rozstrzeloną obsługę tego comba.

Model

 
 public class RaportowanieModel : EntityBase
    {
        public string miesiac { get; set; }
        public string rok { get; set; }
        public string[] rokDataSource { get; set; }
        public string[] miesiacDataSource { get; set; }
        public DataTable raportyWyborDanychDT { get; set; }
        public DataRow raportyWyborDanychCurrentDR { get; set; }
    }

Presenter

 
 public void Initialize(IRaportowanie view)
        {
            zapytanieDataGrid.utworzSELECT("RaportyWyborDanychCalosc_v",
                new List<string> { "*" }, new string[] { "month(dataWaluty)=? AND year(dataWaluty)=?", "dataWaluty DESC" });
            zapytanieDataGrid.dodajParametr("@P1", "int");
            zapytanieDataGrid.dodajParametr("@P2", "int");
            view.raportowanieModel = new Model.RaportowanieModel();
        }

        public void load(IRaportowanie view)
        {
            view.raportowanieModel.rokDataSource=Pomocne.ComboBoxDane.rok();
            view.raportowanieModel.miesiacDataSource=Pomocne.ComboBoxDane.miesiac();
        }

View

 public partial class Raportowanie : BaseViewForm, IRaportowanie
    {
        private Presenters.RaportowaniePresenter presenter = new Presenters.RaportowaniePresenter();

        public Raportowanie()
        {
            InitializeComponent();
            presenter.Initialize(this);
        }


        private void Raportowanie_Load(object sender, EventArgs e)
        {
            presenter.load(this);
            this.rokComboBox.DataSource = raportowanieModel.rokDataSource;
            this.rokComboBox.SelectedIndex = 5;
            this.miesiacComboBox.DataSource = raportowanieModel.miesiacDataSource;
            this.miesiacComboBox.SelectedIndex = DateTime.Now.Month - 1;
            presenter.daneDoDataGrid(this);
        }


        #region IRaportowanie

        public RaportowanieModel raportowanieModel
        {
            get { return this.raportowanieModelBindingSource.Current as RaportowanieModel; }
            set { this.raportowanieModelBindingSource.DataSource = value; }
        }

        public DataTable raportowanieDT
        {
            get { return this.raportowanieDTBindingSource.DataSource as DataTable; }
            set
            {
                this.raportowanieDTBindingSource.DataSource = value;
                this.raportowanieDTBindingSource.ResetBindings(false);
            }
        }

        #endregion

Pozdrawiam,
Zoritt

1

Nie podoba mi się to, a konkretnie zawartość Raportowanie_Load. Jest za mądra, a Widok powinien być tak głupi, jak to tylko możliwe.

Ogólnie mówiąc, są dwa rozwiązania:

  1. Każda kontrolka powinna być powiązana z właściwością z interfejsu Widoku (albo dwiema, jeśli poza wartością wymaga źródła danych), które są ustawiane i odczytywane w odpowiednich metodach Prezentera.
  2. Dobrze skonfigurowane BindingSource, które prawidłowo wiąże właściwości klasy Modelu z właściwościami kontrolek.

Zatem albo:

  1. Wszystkie DataSource i SelectedIndex tych ComboBoxów ukryj we właściwościach zaimplementowanych z IRaportowanie oraz ustawianych w metodzie RaportowaniePresenter.Initialize.
  2. Popraw BindingSource, tylko nie wiem, czy w przypadku takiego dziwnego Modelu jak Twój jest to możliwe.
0

Nieco zniechęciłem się do bindowania comboBox'a z właściwościami modelu. Problem jest taki, że w obsłudze zdarzenia SelectedIndexChanged podbindowana właściwość modelu nie jest jeszcze zmieniona (zmienia się dopiero po opuszczeniu comboBox'a) zatem i tak musiałem ręcznie zmienić wartość tej właściwości ponieważ jest ona (ta wartość) pobierana w prezenterze przez daneDoDataGrid. Może jest na to jakaś rada ale nie wymyśliłem i zostałem przy ręcznej podmianie wartości jak poniżej:

 
private void rokComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.rokComboBox.Visible)
            {
                this.raportowanieModel.rok = this.rokComboBox.SelectedItem.ToString();
                presenter.daneDoDataGrid(this);
            }
        }

Druga sprawa to zmartwiłeś mnie tym "dziwnym modelem" powiem szczerze, spotykać udziwnienia to lubię w Alicji w Krainie Czarów a nie kodzie. Rozumiem, że problem w tym DataTable i DataRow?

Całość po poprawkach:
Model:

 
 public class RaportowanieModel : EntityBase
    {
        public string miesiac { get; set; }
        public string rok { get; set; }
        public DataTable raportyWyborDanychDT { get; set; }
        public DataRow raportyWyborDanychCurrentDR { get; set; }
    }

Presenter:

 
class RaportowaniePresenter
    {
        public delegate void eventWlaczStatusBar();
        public event eventWlaczStatusBar wlaczStatusStrip;
        public delegate void eventWylaczStatusBar();
        public event eventWylaczStatusBar wylaczStatusStrip;
        public delegate void eventProgressBar(int ileProcent, string nazwa);
        public event eventProgressBar progressBar;
        private Pomocne.Zapytanie zapytanieDataGrid;
        
        public void Initialize(IRaportowanie view)
        {
            zapytanieDataGrid = new Pomocne.Zapytanie(view);
            zapytanieDataGrid.utworzSELECT("RaportyWyborDanychCalosc_v",
                new List<string> { "*" }, new string[] { "month(dataWaluty)=? AND year(dataWaluty)=?", "dataWaluty DESC" });
            zapytanieDataGrid.dodajParametr("@P1", "int");
            zapytanieDataGrid.dodajParametr("@P2", "int");
            
            view.rokCBDataSource = Pomocne.ComboBoxDane.rok();
            view.rokCBSelectedIndex = 5;
            view.miesiacCBDataSource = Pomocne.ComboBoxDane.miesiac();
            view.miesiacCBSelectedIndex = DateTime.Now.Month - 1;
            view.raportowanieModel = new Model.RaportowanieModel();
        }

        public void daneDoDataGrid(IRaportowanie view)
        {
            zapytanieDataGrid.parametr[0].Value = view.raportowanieModel.miesiac;
            zapytanieDataGrid.parametr[1].Value = view.raportowanieModel.rok;
            view.raportowanieDT = zapytanieDataGrid.wykonajSelect2DataTable();
        }

View:

 
public partial class Raportowanie : BaseViewForm, IRaportowanie
    {
        private Presenters.RaportowaniePresenter presenter = new Presenters.RaportowaniePresenter();

        public Raportowanie()
        {
            InitializeComponent();
            presenter.Initialize(this);
            toolStripStatusLabel1.Text = "Przetwarzanie danych: ";
            presenter.wlaczStatusStrip+=new RaportowaniePresenter.eventWlaczStatusBar(presenter_wlaczStatusStrip);
            presenter.wylaczStatusStrip+=new RaportowaniePresenter.eventWylaczStatusBar(presenter_wylaczStatusStrip);
            presenter.progressBar+=new RaportowaniePresenter.eventProgressBar(presenter_progressBar);
        }


        private void Raportowanie_Load(object sender, EventArgs e)
        {
            presenter.daneDoDataGrid(this);
        }


        #region IRaportowanie
        public string[] rokCBDataSource
        {
            set { this.rokComboBox.DataSource = value; }
        }

        public int rokCBSelectedIndex
        {
            set { this.rokComboBox.SelectedIndex = value; }
        }

        public string[] miesiacCBDataSource
        {
            set { this.miesiacComboBox.DataSource = value; }
        }

        public int miesiacCBSelectedIndex
        {
            set { this.miesiacComboBox.SelectedIndex = value; }
        }

        public RaportowanieModel raportowanieModel
        {
            get { return this.raportowanieModelBindingSource.Current as RaportowanieModel; }
            set { this.raportowanieModelBindingSource.DataSource = value; }
        }

        public DataTable raportowanieDT
        {
            get { return this.raportowanieDTBindingSource.DataSource as DataTable; }
            set
            {
                this.raportowanieDTBindingSource.DataSource = value;
                this.raportowanieDTBindingSource.ResetBindings(false);
            }
        }
        public DataRow raportowanieCurrentDR 
        {
            get
            {
                if (this.raportowanieDTBindingSource.Current == null) return null;
                else return ((DataRowView)this.raportowanieDTBindingSource.Current).Row;
            }
            set { }
        }
        #endregion

Pozdrawiam,
Zoritt

0

Wrócę do starego tematu ale właśnie mnie olśniło. Poprzedni przykład zawiera błąd polegający na przeniknięciu modelu do widoku czyli:

 
view.raportowanieModel = new Model.RaportowanieModel();

Z opisu MVP wynika, że view nie ma mieć pojęcia o istnieniu modelu.
Podsumowując view buduje obiekt w oparciu o klasę prezentera. Prezenter pobiera dane z widoku poprzez interface oraz (prezenter) buduje obiekt w oparciu o klasę modelu. I wtedy wszystko gra.
Niby nic skomplikowanego ...

Pozdrawiam,
Zoritt

1 użytkowników online, w tym zalogowanych: 0, gości: 1