Ini adalah pendapat saya yang sederhana tentang MVP dan masalah spesifik Anda.
Pertama , apa pun yang dapat berinteraksi dengan pengguna, atau hanya ditampilkan, adalah tampilan . Hukum, perilaku, dan karakteristik tampilan seperti itu dijelaskan oleh antarmuka . Antarmuka itu dapat diimplementasikan menggunakan WinForms UI, UI konsol, UI web atau bahkan tanpa UI sama sekali (biasanya saat menguji penyaji) - implementasi konkret tidak masalah selama mematuhi hukum antarmuka tampilan .
Kedua , tampilan selalu dikontrol oleh presenter . Hukum, perilaku dan karakteristik penyaji semacam itu juga dijelaskan oleh antarmuka . Antarmuka tersebut tidak tertarik pada implementasi tampilan konkret selama mematuhi hukum antarmuka tampilan.
Ketiga , karena penyaji mengontrol pandangannya, untuk meminimalkan ketergantungan, sebenarnya tidak ada gunanya memiliki tampilan yang mengetahui apa pun tentang penyaji. Ada kontrak yang disepakati antara penyaji dan tampilan dan itu dinyatakan oleh antarmuka tampilan.
Implikasi dari Ketiga adalah:
- Presenter tidak memiliki metode apa pun yang dapat dipanggil oleh tampilan, tetapi tampilan tersebut memiliki peristiwa yang dapat dilanggan oleh presenter.
- Presenter tahu pandangannya. Saya lebih suka melakukannya dengan injeksi konstruktor pada presenter beton.
- Pandangan tidak tahu apa yang dikendalikan oleh presenter; itu tidak akan pernah diberikan presenter apapun.
Untuk masalah Anda, di atas mungkin terlihat seperti ini dalam kode yang agak disederhanakan:
interface IConfigurationView
{
event EventHandler SelectConfigurationFile;
void SetConfigurationFile(string fullPath);
void Show();
}
class ConfigurationView : IConfigurationView
{
Form form;
Button selectConfigurationFileButton;
Label fullPathLabel;
public event EventHandler SelectConfigurationFile;
public ConfigurationView()
{
this.selectConfigurationFileButton.Click += delegate
{
var Handler = this.SelectConfigurationFile;
if (Handler != null)
{
Handler(this, EventArgs.Empty);
}
};
}
public void SetConfigurationFile(string fullPath)
{
this.fullPathLabel.Text = fullPath;
}
public void Show()
{
this.form.ShowDialog();
}
}
interface IConfigurationPresenter
{
void ShowView();
}
class ConfigurationPresenter : IConfigurationPresenter
{
Configuration configuration = new Configuration();
IConfigurationView view;
public ConfigurationPresenter(IConfigurationView view)
{
this.view = view;
this.view.SelectConfigurationFile += delegate
{
var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
selectFilePresenter.ShowView();
this.configuration.FullPath = selectFilePresenter.FullPath;
this.view.SetConfigurationFile(this.configuration.FullPath);
};
}
public void ShowView()
{
this.view.SetConfigurationFile(this.configuration.FullPath);
this.view.Show();
}
}
Selain di atas, saya biasanya memiliki IView
antarmuka dasar tempat saya menyimpan fileShow()
dan setiap tampilan pemilik atau judul tampilan yang biasanya menguntungkan pandangan saya.
Untuk pertanyaan Anda:
1. Saat winform dimuat, ia harus mendapatkan tampilan pohon. Apakah saya benar dalam berpikir bahwa tampilan harus memanggil metode seperti: presenter.gettree (), ini pada gilirannya akan mendelegasikan ke model, yang akan mendapatkan data untuk treeview, membuatnya dan mengkonfigurasinya, mengembalikannya ke presenter, yang pada gilirannya akan meneruskan ke tampilan yang kemudian akan dengan mudah menetapkannya ke, katakanlah, panel?
Saya akan menelepon IConfigurationView.SetTreeData(...)
dari IConfigurationPresenter.ShowView()
, tepat sebelum panggilan keIConfigurationView.Show()
2. Apakah ini akan sama untuk semua kontrol data di Winform, karena saya juga memiliki datagridview?
Ya, saya akan menelepon IConfigurationView.SetTableData(...)
untuk itu. Terserah tampilan untuk memformat data yang diberikan padanya. Presenter hanya mematuhi kontrak tampilan yang diinginkan data tabel.
3. Aplikasi Saya, memiliki sejumlah kelas model dengan perakitan yang sama. Ini juga mendukung arsitektur plugin dengan plugin yang perlu dimuat saat startup. Akankah tampilan hanya memanggil metode presenter, yang pada gilirannya akan memanggil metode yang memuat plugin dan menampilkan informasi dalam tampilan? Tingkatan mana yang kemudian akan mengontrol referensi plugin. Apakah tampilan tersebut menyimpan referensi ke mereka atau presenter?
Jika plugin terkait dengan tampilan, maka tampilan harus tahu tentang plugin tersebut, tetapi bukan penyaji. Jika semuanya tentang data dan model, maka tampilan seharusnya tidak ada hubungannya dengan mereka.
4. Apakah saya benar dalam berpikir bahwa view harus menangani setiap hal tentang presentasi, dari warna node tampilan pohon, ukuran datagrid, dll?
Iya. Anggap saja sebagai penyaji yang menyediakan XML yang mendeskripsikan data dan tampilan yang mengambil data dan menerapkan lembar gaya CSS ke dalamnya. Secara konkret, presenter mungkin memanggil IRoadMapView.SetRoadCondition(RoadCondition.Slippery)
dan view kemudian menampilkan jalan dengan warna merah.
Bagaimana dengan data untuk node yang diklik?
5. Jika ketika saya mengklik treenode, haruskah saya melewati node tertentu ke presenter dan kemudian dari situ presenter akan menentukan data apa yang dibutuhkan dan kemudian menanyakan model untuk data itu, sebelum menampilkannya kembali ke tampilan?
Jika memungkinkan, saya akan meneruskan semua data yang diperlukan untuk menampilkan pohon dalam satu tampilan dalam satu bidikan. Tetapi jika beberapa data terlalu besar untuk diteruskan dari awal atau jika sifatnya dinamis dan membutuhkan "snapshot terbaru" dari model (melalui presenter), maka saya akan menambahkan sesuatu seperti event LoadNodeDetailsEventHandler LoadNodeDetails
antarmuka tampilan, sehingga presenter dapat berlangganan padanya, mengambil detail node di LoadNodeDetailsEventArgs.Node
(mungkin melalui beberapa jenis ID-nya) dari model, sehingga tampilan dapat memperbarui detail node yang ditampilkan saat delegasi event handler kembali. Perhatikan bahwa pola asinkron ini mungkin diperlukan jika pengambilan data mungkin terlalu lambat untuk pengalaman pengguna yang baik.