ComboBox w MVP

ZO
  • Rejestracja:około 15 lat
  • Ostatnio:ponad 10 lat
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

Kopiuj
 
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

Kopiuj
 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

Kopiuj
 
 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

edytowany 3x, ostatnio: Zoritt
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:4 dni
  • Lokalizacja:Wrocław
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?

ZO
Teraz mam jasność. Wielkie dzięki!
somekind
Proszę bardzo. Ale jeśli pomogłem, to pisz posty/punktuj/akceptuj, a nie tylko komentujesz.
ZO
Zaraz jak poprawię tego comboBox'a to zawieszę w poście kod, może się komuś przyda
ZO
  • Rejestracja:około 15 lat
  • Ostatnio:ponad 10 lat
0

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

Model

Kopiuj
 
 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

Kopiuj
 
 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

Kopiuj
 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

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:4 dni
  • Lokalizacja:Wrocław
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.
ZO
  • Rejestracja:około 15 lat
  • Ostatnio:ponad 10 lat
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:

Kopiuj
 
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:

Kopiuj
 
 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:

Kopiuj
 
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:

Kopiuj
 
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

ZO
  • Rejestracja:około 15 lat
  • Ostatnio:ponad 10 lat
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:

Kopiuj
 
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

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.