Autor |
Beitrag |
Nally
      
Beiträge: 46
|
Verfasst: Fr 28.11.08 23:09
Hallo,
1.) ich würde gerne wissen wie die Daten in der View eingegeben dem Presenter übergeben werden, in meinem Beispielcode unten wird in der View lediglich der Presenter initiiert und auf das Model zugegriffen in z.B. der DeleteDepartment() Methode. Würde ich die AddDepartment() Methode auch noch implementieren, dann muss ich z.B. des Beispiels Willen 3 strings entgegen nehmen: siehe weiter unten nach "ODER"
DepartmentPresenter.cs
department.department_name = view. <<<<<<<<--------------------- wie bekomme ich den string aus der departmentTextBox in den department_name?
z.B. mit view.DepartentName()
C#-Quelltext 1: 2: 3: 4:
| public String DepartmentName() { return departmentTextBox.Text; } |
doch das war noch einfach wenn nur ein String zurückgegeben werden muss. Was aber wenn es mehrere Strings sind sprich gleich eine Entität/Objekt?
Doch mit folgender Lösung habe ich ein Problem vielleicht Ihr auch ^^ Eine Entität sollte doch nicht in der View instanziiert werden??
ODER
View:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| public DEPARTMENT GetDepartment() { DEPARTMENT department = new DEPARTMENT(); department.department_name = departmentTextBox.Text; department.code = departmentcodeTextBox.Text; department.boss = departmentbossTextBox.Text;
return department; } |
doch department.department_name = view.GetDepartment() <<<<<<<<===--------------------- siehe codelücke weiter unten in der Presenter Klasse auch mit dem Pfeil...
2.) Macht man das in C# so, dass Daten zwischen View und Presenter via events ausgetauscht werden? Der Presenter steuert ja die View also muss das irgendwie gemacht werden...
View:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:
| using System; using System.Windows.Forms;
namespace Company { public partial class MainWindowView : Form , IDepartmentView { private IDepartmentPresenter departmentPresenter;
public event VoidEventHandler AddDepartment; public event VoidEventHandler DeleteDepartment;
public MainWindowView() { InitializeComponent(); departmentPresenter = new DepartmentPresenter(this); }
private void addDepartmentButton_Click(object sender, EventArgs e) { if (AddDepartment != null) AddDepartment(); }
private void deleteDepartmentButton_Click(object sender, EventArgs e) { if (DeleteDepartment != null) DeleteDepartment(); }
public DEPARTMENT CurrentDepartment { get { return (DEPARTMENT)departmentListBox.SelectedItem; } set { } } } } |
Presenter:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
| using System; using System.Collections.Generic; using System.Text;
namespace Company { class DepartmentPresenter : IDepartmentPresenter { private IDepartmentView view;
public DepartmentPresenter(IDepartmentView view) { this.view = view;
this.view.DeleteDepartment += this.view_DeleteDepartment; this.view.AddDepartment += this.view_AddDepartment; }
public virtual void view_DeleteDepartment() { DEPARTMENT department = view.CurrentDepartment;
try { using (CompanyEntities objectContext = new CompanyEntities()) { objectContext.DeleteObject(department); objectContext.SaveChanges(); } } catch (Exception ex) { throw ex; } }
public virtual void view_AddDepartment() { DEPARTMENT department = new DEPARTMENT();
try { using (CompanyEntities objectContext = new CompanyEntities()) { objectContext.AddToDEPARTMENT(department); objectContext.SaveChanges(); } } catch (Exception ex) {
throw ex; } } } } |
Interface für Presenter:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| namespace Company {
public interface IDepartmentPresenter { void view_AddDepartment(); void view_DeleteDepartment(); } } |
Interface für View:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| namespace Company { public delegate void VoidEventHandler();
public interface IDepartmentView { DEPARTMENT CurrentDepartment { get; set; }
event VoidEventHandler AddDepartment; event VoidEventHandler DeleteDepartment;
} } | Moderiert von Christian S.: Topic aus C# - Die Sprache verschoben am Fr 28.11.2008 um 22:15
|
|
jaenicke
      
Beiträge: 19313
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 29.11.08 02:08
Was mir bei dir auffällt ist, dass dein View den Presenter erzeugt. Der Presenter sollte aber alles steuern. Die View sollte nur gesagt bekommen "Zeige das und das an" oder "Lasse dieses Objekt editieren", aber nicht selbst etwas steuern.
Jede Aktion des Benutzers wird dann an den Presenter weitergeleitet. Und wenn beispielsweise ein neuer Eintrag erstellt wird, dann kann dein View durchaus ein neues Objekt erstellen, füllen und an deinen Presenter weiterleiten. Dieser wiederum leitet es dann beispielsweise zur Speicherung an deine Datenspeicherung weiter.
Was passiert ist also normalerweise:
In deiner main-Methode wird der Presenter erstellt. Dieser wiederum initialisiert dann sowohl dein Datenmodell als auch die entsprechende View. Dadurch wird es auch so einfach die View auszutauschen. Es reicht eine andere View zu erzeugen an der Stelle.
|
|
Nally 
      
Beiträge: 46
|
Verfasst: So 30.11.08 20:52
Zitat: | Was mir bei dir auffällt ist, dass dein View den Presenter erzeugt. Der Presenter sollte aber alles steuern. Die View sollte nur gesagt bekommen "Zeige das und das an" oder "Lasse dieses Objekt editieren", aber nicht selbst etwas steuern. |
richtig die View erzeugt den Presenter, DENN das WPF + EF sample von DataPoint macht es genau so , moment ich suche es:
da --> msdn.microsoft.com/d...gazine/cc700340.aspx
lad dir mal die .exe runter, kannst selber nachprüfen , dass der John Papa Mist gebaut hat dann...
Zitat: | Was passiert ist also normalerweise:
In deiner main-Methode wird der Presenter erstellt. Dieser wiederum initialisiert dann sowohl dein Datenmodell als auch die entsprechende View. Dadurch wird es auch so einfach die View auszutauschen. Es reicht eine andere View zu erzeugen an der Stelle. |
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| namespace Company { static class Program { [STAThread] static void Main() { MainWindowView mainWindowView = new MainWindowView(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(mainWindowView);
DepartmentPresenter presenter = new DepartmentPresenter(); } } } |
1.) So die Main Methode erstellt wie von dir verlangt den Presenter!
2.) soll ich nun dem Presenter Kunstruktor die view "mainWindow" übergeben?
3.) Auf meine Fragen bist du nur sehr unscharf eingegangen...
"2.) Macht man das in C# so, dass Daten zwischen View und Presenter via events ausgetauscht werden? Der Presenter steuert ja die View also muss das irgendwie gemacht werden... "
kannst du dazu noch was sagen? Ich weiß um die richtige Kommunikation zwischen 2 Forms mit delegaten. Doch wie geht das mit dem Datenaustausch zwischen view+presenter?
|
|
jaenicke
      
Beiträge: 19313
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 30.11.08 22:20
Nally hat folgendes geschrieben : | 2.) soll ich nun dem Presenter Kunstruktor die view "mainWindow" übergeben? |
So würde ich es machen, ja. So kannst du an der Stelle die eine View durch eine andere austauschen ohne sonst irgend etwas zu verändern.
Wenn man es andersherum macht, wie das Beispiel es tut wie du sagst (ich habe es mir nicht angeschaut), dann verfehlt das etwas diese Austauschbarkeit, bzw. es macht mehr Mühe die View auszutauschen. Außerdem soll die View eben eigentlich nichts anderes machen als darstellen.
Nally hat folgendes geschrieben : | "2.) Macht man das in C# so, dass Daten zwischen View und Presenter via events ausgetauscht werden? Der Presenter steuert ja die View also muss das irgendwie gemacht werden... " |
Dazu muss ich sagen, dass ich C# nicht so gut kann, dass ich mir spezielle Vorgehensweisen von C# besonders gut angeeignet hätte, d.h. ich schreibe zwar auch Programme darin, aber das mache ich eher so wie ich es aus Delphi gewohnt bin soweit das geht.
Man definiert Schnittstellen, das ist ja genau das besondere dieses Patterns gegenüber MVC, die alle notwendigen Funktionen enthalten und benutzt diese. In einem solchen Fall hier würde ich jeweils ein Interface mit allen Datenübergabefunktionen etc. für View und Presenter definieren. Diese müssten dann jeweils implementiert werden und die Objekte werden als Typ des Interfaces übergeben.
Die View kennt also die Schnittstelle zum Presenter und umgekehrt, mehr nicht. Wird jetzt die View bspw. ausgetauscht, dann merkt der Presenter nichts davon, denn die andere View steuert genauso nur die Schnittstelle an und die View implementiert die selbe Schnittstelle wie jede andere View.
Diese Interfaces hast du ja auch bereits bei dir.
Was genau in der View und was im Presenter implementiert wird ist schwierig zu definieren. Grundsätzlich würde ich so viel wie möglich der Logik in den Presenter legen und alles was nur mit der speziellen Oberfläche zu tun hat in die View.
Als Beispiel nehme ich mal einen Editor für eine Liste von Personen in einer Datenbank, ich denke mal das kommt dem nahe was dein Beispiel ist. Ich selbst habe eher mit dem MVC Pattern gearbeitet bisher, aber der Unterschied ist ja nur eine stärkere Trennung der View vom Modell.
Start, die Anwendung wird gestartet. Der Presenter initialisiert den Datenzugriff und zeigt die View an. Dabei wird das Interface der View im Presenter gespeichert und das des Presenters der View übergeben.
Danach setzt der Presenter die View in den Editiermodus und übergibt den aktuellen (in diesem Fall den ersten) Datensatz dafür, der View zeigt diese daraufhin an. In der View kann der Benutzer jetzt die Daten editieren und drückt dann auf speichern. Dies wird dem Presenter mitgeteilt, der editierte Datensatz wird dabei mit zurückgegeben. Der Presenter fragt den aktuellen Modus des Views ab und aktualisiert daraufhin den bestehenden Datensatz.
Jetzt drückt der Benutzer auf weiter, der Presenter bekommt diese Anforderung, setzt erneut den Editiermodus und übergibt den Datensatz etc.
Jetzt drückt der Benutzer auf neuen Datensatz. Der Presenter setzt die View in den Neu-erstellen-Modus und übergibt einen leeren Datensatz. Drückt der Benutzer jetzt auf speichern, dann bekommt der Presenter davon wiederum Bescheid inkl. des aktuellen Datensatzes, fragt den aktuellen Modus der View ab und fügt den Datensatz daraufhin als neuen Datensatz hinzu. Zudem setzt er den Editiermodus für die View und übergibt dabei erneut den aktuellen (gerade gespeicherten) Datensatz.
Jetzt drückt der Benutzer auf Löschen, der Presenter fragt den aktuellen Modus de Viewers ab, und da gerade ein bestehender Datensatz zum Editieren angezeigt wird, löscht er diesen und veranlasst die Anzeige des nächsten Datensatzes.
Wäre es ein neuer Datensatz gewesen, dann wäre die View in dem entsprechenden Modus gewesen und der Presenter würde erkennen, dass er nichts löschen muss, da der Datensatz noch gar nicht in der DB ist.
So würde ich das umsetzen. Man kann das sicher auch anders machen, dies wäre meine Interpretation des Patterns.
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: So 30.11.08 22:53
Zitat: | 1.) ich würde gerne wissen wie die Daten in der View eingegeben dem Presenter übergeben werden, in meinem Beispielcode unten wird in der View lediglich der Presenter initiiert und auf das Model zugegriffen in z.B. der DeleteDepartment() Methode. Würde ich die AddDepartment() Methode auch noch implementieren, dann muss ich z.B. des Beispiels Willen 3 strings entgegen nehmen: siehe weiter unten nach "ODER" |
Dem Presenter übergibt man nichts. Der holt sich die Daten gegebenfalls aus dem View (über das Interface des Views) wenn er sie braucht.
Wie er das macht hängt von der MVP Variante ab die du benutzt.
Grob gibts da 2 Richtungen.
A.) Passive View - Der View ist eigentlich richtig dumm hält aber für jeden einzelnen Wert der im View dargestellt werden kann eine Property zum Abfragen in seinem Interface bereit(also z.B. deinen DepartmentName).
B.) Supervising Controller - Der View beherscht zumindest Databinding. Heißt der Presenter übergibt dem View eine Modelklasse das dann per Databinding an die Controls des Views durch den View gebunden werden. Der View muß dann zumindest also das Binding an die Controls übernehmen un dwird damit etwas intelligenter sein Interface wird aber deutlich einfacher.
Persönlich tendiere ich zu B. Einfach weil ich Databinding mag und A. sehr viel Aufwand darstellt.
Zitat: | doch das war noch einfach wenn nur ein String zurückgegeben werden muss. Was aber wenn es mehrere Strings sind sprich gleich eine Entität/Objekt?
Doch mit folgender Lösung habe ich ein Problem vielleicht Ihr auch ^^ Eine Entität sollte doch nicht in der View instanziiert werden?? |
Wenn der View ein neue Entität braucht sollte es diesen beim Presenter anfordern. Und der Presenter wiederum von seiner Business Logik Schicht.
Zitat: | 2.) Macht man das in C# so, dass Daten zwischen View und Presenter via events ausgetauscht werden? Der Presenter steuert ja die View also muss das irgendwie gemacht werden... |
Ja. Dein View sollte Events via seinem Interface veröffentlichen an die sich der Presenter binden kann. so wie in deinem IDepartmentView Interface. Wobei du deinen Events ruhig die betroffenen Entitäten schon mitgeben kannst.
Zu der Frage, wer soll wenn erzeugen, bin ich dafür das der View eher den Presenter erzeugen sollte und nicht umgekehrt.
Der Presenter hält Business Logik (zumindest teilweise) während der View eher dumm ist.
Wen du etwas Wiederverwenden möchtest wirst du dich aber mit Klassen die keine Abhängigkeiten leichter tun als mit denen die Abhängigkeiten haben.
Du solltest also dazu streben das dein fetten Klassen insbesondere diejenigen die Businesslogik haben (Presenter, Modellklassen etc.) möglichst wenig Abhängigkeiten haben. Idealerweise sollten diese der POCO Anforderung genügen.
Der Ansatz View erzeugt Presenter ist auch vom Testgesichtspunkt her besser. Da du nun Unittest auf deine Logik im Presenter abfeuern kannst ohne das dir Abhängigkeiten auf die GUI in die Quere kommen.
Aber auch diese Abhängigkeit, View erzeugt Presenter, ist letztlich nur suboptimal. Die meisten Frameworks die MVP anbieten kombinieren MVP deshalb mit einem Dependency Injection Framework.
Das läuft etwa darauf hinaus das eine 3.te Instanz (der Dependency Injection Container) die Abhängigkeit zwischen Klassen herstellt und die Beteiligten sich gegenseitig wirklich nur über ihre Interfaces kennen und keiner eine konkrete Implementierung des jeweils anderen.
|
|
Nally 
      
Beiträge: 46
|
Verfasst: So 30.11.08 23:12
Zitat: | 2.) soll ich nun dem Presenter Kunstruktor die view "mainWindow" übergeben? |
So würde ich es machen, ja. So kannst du an der Stelle die eine View durch eine andere austauschen ohne sonst irgend etwas zu verändern.
Wenn man es andersherum macht, wie das Beispiel es tut wie du sagst (ich habe es mir nicht angeschaut), dann verfehlt das etwas diese Austauschbarkeit, bzw. es macht mehr Mühe die View auszutauschen. Außerdem soll die View eben eigentlich nichts anderes machen als darstellen.[/quote]
Hm... was ist aber mit Fenstern die von einem Button_Click aus dem MainWindow geöffnet werden? ala myForm.ShowDialog() Hier ist die View zuständig für das Anzeigen einer anderen View... ich finde dieses Austauschbar-entschuldige- gelaber ätzend, denn es macht zu 99% niemand, aber es wird ein Riesenaufwand darum betrieben.
Frage: Vor allem WO instanziiere ich den Presenter, wenn ich in der MainWindow ein 2. Eingabe Window aufrufe ?
MVC in Java geht über Observer/Observable so kenne ich das
Schnittstellen haben für 1 positiven + 1 negativen "Zweck":
+ Methodenrümpfe werden im Interface vorgegeben, so dass andere gezwungen sind Implementierungen der Methoden zu schreiben.
- Implementierte Methoden in der View z.B. bei meinem ganz obigen Code z.B. die Methode
DEPARTMENT CurrentDepartment { get; set; }; geht einfach verloren, wenn die View ausgetauscht wird... daher weiß ich beim besten Willen nicht, so sehr ich es
auch versuche, was an der Austauschbarkeit so toll ist.
Zitat: | Start, die Anwendung wird gestartet. Der Presenter initialisiert den Datenzugriff und zeigt die View an. Dabei wird das Interface der View im Presenter gespeichert und das des Presenters der View übergeben.
Danach setzt der Presenter die View in den Editiermodus und übergibt den aktuellen (in diesem Fall den ersten) Datensatz dafür, der View zeigt diese daraufhin an. In der View kann der Benutzer jetzt die Daten editieren und drückt dann auf speichern. Dies wird dem Presenter mitgeteilt, der editierte Datensatz wird dabei mit zurückgegeben. Der Presenter fragt den aktuellen Modus des Views ab und aktualisiert daraufhin den bestehenden Datensatz.
Jetzt drückt der Benutzer auf weiter, der Presenter bekommt diese Anforderung, setzt erneut den Editiermodus und übergibt den Datensatz etc.
Jetzt drückt der Benutzer auf neuen Datensatz. Der Presenter setzt die View in den Neu-erstellen-Modus und übergibt einen leeren Datensatz. Drückt der Benutzer jetzt auf speichern, dann bekommt der Presenter davon wiederum Bescheid inkl. des aktuellen Datensatzes, fragt den aktuellen Modus der View ab und fügt den Datensatz daraufhin als neuen Datensatz hinzu. Zudem setzt er den Editiermodus für die View und übergibt dabei erneut den aktuellen (gerade gespeicherten) Datensatz.
Jetzt drückt der Benutzer auf Löschen, der Presenter fragt den aktuellen Modus de Viewers ab, und da gerade ein bestehender Datensatz zum Editieren angezeigt wird, löscht er diesen und veranlasst die Anzeige des nächsten Datensatzes.
Wäre es ein neuer Datensatz gewesen, dann wäre die View in dem entsprechenden Modus gewesen und der Presenter würde erkennen, dass er nichts löschen muss, da der Datensatz noch gar nicht in der DB ist.
So würde ich das umsetzen. Man kann das sicher auch anders machen, dies wäre meine Interpretation des Patterns. |
Das hört sich gräulich umständlich an, dies in der Praxis so umzusetzen.
Zuletzt bearbeitet von Nally am Mo 01.12.08 00:07, insgesamt 1-mal bearbeitet
|
|
Nally 
      
Beiträge: 46
|
Verfasst: So 30.11.08 23:48
Zitat: | ich würde gerne wissen wie die Daten in der View eingegeben dem Presenter übergeben werden, in meinem Beispielcode unten wird in der View lediglich der Presenter initiiert und auf das Model zugegriffen in z.B. der DeleteDepartment() Methode. Würde ich die AddDepartment() Methode auch noch implementieren, dann muss ich z.B. des Beispiels Willen 3 strings entgegen nehmen: siehe weiter unten nach "ODER" |
Dem Presenter übergibt man nichts. Der holt sich die Daten gegebenfalls aus dem View (über das Interface des Views) wenn er sie braucht.
Wie er das macht hängt von der MVP Variante ab die du benutzt.
Grob gibts da 2 Richtungen.
A.) Passive View - Der View ist eigentlich richtig dumm hält aber für jeden einzelnen Wert der im View dargestellt werden kann eine Property zum Abfragen in seinem Interface bereit(also z.B. deinen DepartmentName).
B.) Supervising Controller - Der View beherscht zumindest Databinding. Heißt der Presenter übergibt dem View eine Modelklasse das dann per Databinding an die Controls des Views durch den View gebunden werden. Der View muß dann zumindest also das Binding an die Controls übernehmen un dwird damit etwas intelligenter sein Interface wird aber deutlich einfacher.
Persönlich tendiere ich zu B. Einfach weil ich Databinding mag und A. sehr viel Aufwand darstellt. [/quote] Ich tendiere auch zu Methode B
Zitat: | doch das war noch einfach wenn nur ein String zurückgegeben werden muss. Was aber wenn es mehrere Strings sind sprich gleich eine Entität/Objekt?
Doch mit folgender Lösung habe ich ein Problem vielleicht Ihr auch ^^ Eine Entität sollte doch nicht in der View instanziiert werden?? |
Zitat: | Wenn der View ein neue Entität braucht sollte es diesen beim Presenter anfordern. Und der Presenter wiederum von seiner Business Logik Schicht. |
Das gibt mir zu denken... denn die View stellt nur dar und sollte nichts anfordern!!!??? Wieso sagst du das? Gehn wir von meinem Beispiel aus, dass der Presenter in der View-Konstruktor erzeugt wird, dann könnte ich in der View schreiben: presenter.GetEntity(); das sollte man doch nicht machen...
Zitat: | 2.) Macht man das in C# so, dass Daten zwischen View und Presenter via events ausgetauscht werden? Der Presenter steuert ja die View also muss das irgendwie gemacht werden... |
Zitat: |
Ja. Dein View sollte Events via seinem Interface veröffentlichen an die sich der Presenter binden kann. so wie in deinem IDepartmentView Interface. Wobei du deinen Events ruhig die betroffenen Entitäten schon mitgeben kannst. |
Den Events die Entitäten mitgeben:
Hm sorry wie war meine Frage, finde Sie nicht mehr, warum will/sollte ich den Events Entitäten mitgeben -steh auf Schlauch...-
EDIT: also rufe ich aus dem Presenter heraus folgendes auf: view.GetDepartment(); wie verbinde ich vorherigen Aufruf nun mit einem event dem ich die Entität übergebe?
Da die Entität nicht in der View erzeugt werden soll, erzeuge ich sie in dem Presenter und übergebe die Entität der View via view.GetDepartment(new DEPARTMENT()); ??
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| public DEPARTMENT GetDepartment(DEPARTMENT department) { department.department_name = departmentTextBox.Text; department.code = departmentcodeTextBox.Text; department.boss = departmentbossTextBox.Text;
return department; } |
Zitat: | Zu der Frage, wer soll wenn erzeugen, bin ich dafür das der View eher den Presenter erzeugen sollte und nicht umgekehrt. |
Also war das MVP+EF Beispiel von John Papa auf Datapoint doch nicht falsch... oder MVP ist abhängig von subjektiven Meinungen - grrrr....-
Zitat: | Der Presenter hält Business Logik (zumindest teilweise) während der View eher dumm ist.
Wen du etwas Wiederverwenden möchtest wirst du dich aber mit Klassen die keine Abhängigkeiten leichter tun als mit denen die Abhängigkeiten haben.
Du solltest also dazu streben das dein fetten Klassen insbesondere diejenigen die Businesslogik haben (Presenter, Modellklassen etc.) möglichst wenig Abhängigkeiten haben. Idealerweise sollten diese der POCO Anforderung genügen.
Der Ansatz View erzeugt Presenter ist auch vom Testgesichtspunkt her besser. Da du nun Unittest auf deine Logik im Presenter abfeuern kannst ohne das dir Abhängigkeiten auf die GUI in die Quere kommen. |
ja, da stimme ich dir zu!
Zitat: | Aber auch diese Abhängigkeit, View erzeugt Presenter, ist letztlich nur suboptimal. Die meisten Frameworks die MVP anbieten kombinieren MVP deshalb mit einem Dependency Injection Framework.
Das läuft etwa darauf hinaus das eine 3.te Instanz (der Dependency Injection Container) die Abhängigkeit zwischen Klassen herstellt und die Beteiligten sich gegenseitig wirklich nur über ihre Interfaces kennen und keiner eine konkrete Implementierung des jeweils anderen. |
Hast du dein Programm www.mailstore.com/en/ nach den letzten Kriterien (Dependency Injection Framework) programmiert? 
|
|
jaenicke
      
Beiträge: 19313
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 01.12.08 00:07
Grundsätzlich hört sich so etwas vielleicht kompliziert an und für kleinere Programme lohnt es sich auch nicht unbedingt das einzusetzen. Aber gerade wenn mehrere Personen an einem Programm arbeiten lohnt es sich solche Pattern einzusetzen.
Wenn es kleinere Programme sind, dann ist auch das Problem der Wiederverwendbarkeit und Austauschbarkeit einzelner Teile nicht so wichtig. Wenn du aber eine Oberfläche fest verdrahtet hast mit dem Rest und dann diese nicht mehr verwenden kannst, weil sich Rahmenbedingungen ändern, dann hast du bei größeren Projekten evtl. zehntausende von Zeilen Code und sehr viel Arbeitszeit investiert, die einfach nicht mehr benutzt werden können und neu geschrieben werden müssen.
Mein bisher größtes Projekt, an dem ich in größerem Umfang beteiligt war, umfasste ca. 1.100.000 Zeilen Quelltext und im Laufe der Zeit zwischen 12 und 17 Programmierer. Und da war es sehr wichtig, dass einzelne Teile unabhängig voneinander funktionierten. Zunächst gab es eine Oberfläche aus Standardkomponenten. Langweilig, grau in grau. Ein Programmierer hat dann zusammen mit einem Grafiker eine andere Oberfläche entworfen. Am Ende wurde dann diese OpenGL Oberfläche als Option angeboten.
Zudem gibt es eine Kommandozeilenversion, die zwar nur wenige der verfügbaren Funktionen bedient, aber genauso über das Standardinterface für eine View funktionierte.
(Dort wurde eine MVC-ähnliche Grundstruktur benutzt, wenn auch nicht komplett identisch.)
Nally hat folgendes geschrieben : | Also war das MVP+EF Beispiel von John Papa auf Datapoint doch nicht falsch... oder MVP ist abhängig von subjektiven Meinungen - grrrr....- |
Falsch oder richtig ist so eine Sache, ich finde dass es in die View nicht hineingehört, da diese keine steuernde Funktion hat. Das kann man auch anders sehen und es gibt ja auch die beiden Modelle wo die View mehr oder weniger "zu sagen" hat.
Ich selbst setze eher eine zentrale Startroutine ein, die alle Komponenten der Reihe nach erzeugt und initialisiert. Das erleichtert die Fehlersuche und das Hinzufügen oder Ändern von Komponenten. Wenn die View den Presenter erzeugt, dann heißt das, dass die Initialisierung nicht zentral stattfindet. Erst wird die View erzeugt, dann wird in dieser der Presenter erzeugt, dann erzeugt dieser die Datenverwaltung, etc., und wenn man den Start nachvollziehen will, hangelt man sich von einer Stelle zur anderen. Sowas finde ich ziemlich unübersichtlich.
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mo 01.12.08 01:25
Zitat: |
Das gibt mir zu denken... denn die View stellt nur dar und sollte nichts anfordern!!!??? Wieso sagst du das? Gehn wir von meinem Beispiel aus, dass der Presenter in der View-Konstruktor erzeugt wird, dann könnte ich in der View schreiben: presenter.GetEntity(); das sollte man doch nicht machen...
|
Der View muß Methoden vom Presenter aufrufen können, sonst könnte der View ja nichts erledigen auch ein Event ist letztlich nur ein Methodenaufruf.
In den meisten Fällen hat man schon ein Objekt parat das man in einem View anzeigen will in dem Fall ist klar das der Presenter dieses Objekt einfach in den View reinschiebt.
Es gibt aber auch Fälle wo vom View aus durch Userinteraktion ein neues Objekt in den selben View hineinholen muß. Das kann man per Event erledigen so das die Userinteraktion ein Event im Presenter aufruft der darauf das neue Objekt in den View schiebt. Ich hätte aber auch kein Problem damit wenn der View eine Methode des Presenters aufruft solange der Methodenaufruf das einzige ist was der View tut und der Rest im Presenter oder noch dahinter erledigt wird.
Zitat: | also rufe ich aus dem Presenter heraus folgendes auf: view.GetDepartment(); wie verbinde ich vorherigen Aufruf nun mit einem event dem ich die Entität übergebe?
Da die Entität nicht in der View erzeugt werden soll, erzeuge ich sie in dem Presenter und übergebe die Entität der View via view.GetDepartment(new DEPARTMENT()); ?? |
Ich fand es komisch das du void Events feuerst ohne Daten. Wenn die Events schon Add und Delete heißen und du dich für B. entschieden hast  kannst du doch einfach das betroffene Objekt mit in den Event packen. Klassischer Eventaufbau halt mit EventArgs in denen dann das betroffene Objekt steckt.
Zum View view.GetDepartment(new DEPARTMENT()) ...
.... wieso GET das ist ein Setter.
.... du solltest dir das Department im Presenter noch merken damit der Presenter weiterhin mit dem Department arbeiten kann. Es hilft wenn der Presenter weiterhin selbst eine Referenz auf das/die Objekte im View hat um darauf zu wirken.
Zitat: | Also war das MVP+EF Beispiel von John Papa auf Datapoint doch nicht falsch... oder MVP ist abhängig von subjektiven Meinungen - grrrr....- |
Patterns sind Vorschläge. Nichts an das man sich sklavisch halten muß. Wenn man gute Gründe hat diese seinem Anwendungsfall anzupassen braucht man kein schlechtes Gewissen zu haben dies auch zu tun.
In diesem Fall würde ich normalerweise dem Autor zustimmen es kann aber auch Gründe geben es anders zu machen.
Zitat: | Hast du dein Programm www.mailstore.com/en/ nach den letzten Kriterien (Dependency Injection Framework) programmiert?  |
Da würden ein paar Kollegen sauer sein wenn du es als mein Program darstellst ich bin nur eine Randfigur  Wie hast du mich da gefunden?
Nein die Mailstore UI basiert nicht auf einem DI Framework und auch nicht auf MVP. Für den Overhead eines solchen Ansatzes fehlt Mailstore einfach die nötige GUI Masse um das zu rechtfertigen.
|
|
Nally 
      
Beiträge: 46
|
Verfasst: Di 02.12.08 00:06
Zitat: | Das kann man per Event erledigen so das die Userinteraktion ein Event im Presenter aufruft der darauf das neue Objekt in den View schiebt. |
1.)
sprich Event ruft presenter welcher wiederum das neue Objekt in die View schiebt...da komme ich durcheinander... mache ich das jetzt mit events ODER benutze ich im presenter die view.MeineMethodeUmObjektInViewZuScHieben() ?? Denn hier in meinem Buch steht ja auch:"...events stellen einen Mechanismus dar mit dem Klassen auf Geschehnisse in einer anderen Klassen reagieren können...". für was dann der view typ dem presenter übergeben?
EDIT: ok das view brauche ich natürlich im presenter für view.DepartmentAdded += new MainWindowView.DepartmentAddedEventHandler(AddDepartment);
2.) Würdest du für die events auch dies benutzen: Zitat: | The Action<> object lets you specify an action to be performed on an object. |
Zitat: |
Ich fand es komisch das du void Events feuerst ohne Daten. Wenn die Events schon Add und Delete heißen und du dich für B. entschieden hast kannst du doch einfach das betroffene Objekt mit in den Event packen. Klassischer Eventaufbau halt mit EventArgs in denen dann das betroffene Objekt steckt. |
ja weil ich das Beispiel von john papa so übernommen habe  ich less mir gerade nochmals hier im Buch alles über delegates + events an und poste dann ein neues Beispiel in der Hoffnung es ist gut so
3.)Vor allem wie du sagtest, events sind ja auch Methoden, würdest du dann alle events im interface deklarieren im HInblick auf MVP? Ich kann ja auch Daten zwischen 2 Klassen austauschen ohne interface...
Zitat: | Da würden ein paar Kollegen sauer sein wenn du es als mein Program darstellst ich bin nur eine Randfigur Wie hast du mich da gefunden? |
Naja, du hast in deiner Signatur einen www link...
4.) Wie heißt denn eure asp.net Image Library ?
Also ich klicke auf ein thumbnail-screenshot dann fadet das Bild in xxl herein und fadet beim Schließen auch zurück?
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 02.12.08 13:42
Ich habe mal ein kurzes Beispiel gestrickt um dir zu zeigen wie das mit Events laufen könnte.
In diesem Fall haben ich mal ein speichern Event angenommen der den View aber nicht schließt. (z.B. für eine Art zwischenspeichern) Kein gutes Beispiel mir viel aber etwas besseres grad nicht ein.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69:
| public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
public class EventArgs<T> : EventArgs { private T _data;
public EventArgs(T data) { _data = data; }
public T Data { get { return _data; } } }
public interface IMyView { void BindToDataSource(MyBusinessEntity myBusinessEntity); event EventHandler<EventArgs<MyBusinessEntity>> OnSave; }
public partial class MyView : UserControl, IMyView { private MyBusinessEntity _myBusinessEntity;
#region IMyView Members
public void BindToDataSource(MyBusinessEntity myBusinessEntity) { _myBusinessEntity = myBusinessEntity; myBindingSource.DataSource = _myBusinessEntity; } public event EventHandler<EventArgs<MyBusinessEntity>> OnSave; #endregion private void btnSave_ItemClick(object sender, ItemClickEventArgs e) { if (OnSave != null) { OnSave(this, new EventArgs<MyBusinessEntity>(_myBusinessEntity)); } } }
public partial class MyPresenter { private IMyView _myView; internal MyPresenter(IMyView myView) { _myView = myView; myView.OnSave += View_OnSave; } private void View_OnSave(object sender, EventArgs<MyBusinessEntity> e) { MyBusinessEntity entity = mySaveService.Save(e.Data); _myView.BindToDataSource(entity); } } |
|
|
Nally 
      
Beiträge: 46
|
Verfasst: Di 02.12.08 18:18
man man man manchmal könnt ich mich selber hauen. Da bin ich fast an deime code verzweifelt, da ich nicht merkte, dass da noch mehr ist man muss nur scrollen...
schaus mir gerade an und melde mich wieder! Danke dir!
Hier übergibts du _myBusinessEntity, doch woher nimmst du die? Die muss ja wo instanziiert sein. Und in der View sollte man ja keine Model-Klassen instanziieren!
Dein Beispiel ist zwar stimmig für mich nur fehlt eben die Übergabe von view-daten an den presenter. Das würde mich interessieren wie du das machst, denn in der View aufrufen: presenterDepartment.AddDepartment(string departmentname); kanns ja nicht sein, soll die View ja nur darstellen...
C#-Quelltext 1:
| OnSave(this, new EventArgs<MyBusinessEntity>(_myBusinessEntity)); |
würde das gehen? Somit würde ich ja sofort den Inhalt der TextBox der Entität übergeben...
C#-Quelltext 1:
| OnSave(this, new EventArgs<MyBusinessEntity>(new DEPARTMENT() { department_name = departmentTextBox.Text })); |
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 02.12.08 18:52
Zitat: | Hier übergibts du _myBusinessEntity, doch woher nimmst du die? Die muss ja wo instanziiert sein. Und in der View sollte man ja keine Model-Klassen instanziieren! |
Die solltest du dir von (d)einer Businessschicht holen. Nur dort sollte das Instanzieren von BusinessEntities (Business Objekte) erlaubt sein, weil nur dort das komplette Wissen über ein solche Objekt existieren sollte, also z.B. das setzen kontextabhängiger Defaultwerte oder das Einhängen dieses Objekts in eine größe Modellstruktur wenn nötig.
|
|
Nally 
      
Beiträge: 46
|
Verfasst: Di 02.12.08 20:49
Ralf Jansen hat folgendes geschrieben : | Zitat: | Hier übergibts du _myBusinessEntity, doch woher nimmst du die? Die muss ja wo instanziiert sein. Und in der View sollte man ja keine Model-Klassen instanziieren! |
Die solltest du dir von (d)einer Businessschicht holen. Nur dort sollte das Instanzieren von BusinessEntities (Business Objekte) erlaubt sein, weil nur dort das komplette Wissen über ein solche Objekt existieren sollte, also z.B. das setzen kontextabhängiger Defaultwerte oder das Einhängen dieses Objekts in eine größe Modellstruktur wenn nötig. |
so ?? selbst wenns so ok wäre bringt mir das nichts denn die view übergibt ja nirgends die Daten in deinem Beispiel von daher fällt mir jetzt nichts ein... Ich verstehe delegates, methoden  und events doch das ganze so verbinden über 2 Klassen damit die Daten vom Presenter geholt und zurückgeliefert werden an die View, dafür fehlt mir das Verständnis. Was ich doch nicht an deinem Beispiel mag - jetzt erst aufgefallen ^^ - ist z.B. das: es muss doch nicht sein bzw. darf nicht, dass die View in Berührung kommt mit dem Model, denn erzeugt werden soll das Model ja in der Business Logic. Was mich am meisten nervt, dass es wirklich keine englische/deutsche Lektüre zu MVP gibt. Nur die zusammengeschusterten blog links tuns irgendwie nicht... Ich denke, wenn ichs die Woche nicht noch blicke sprich es geschieht ein Wunder, dann mache ichs halt auf die althergebrachte Art... dennoch vielen dank für deine Mühe!
C#-Quelltext 1: 2: 3:
| public partial class MyView : UserControl, IMyView { private MyBusinessEntity _myBusinessEntity; |
C#-Quelltext 1: 2: 3: 4: 5: 6: 7:
| private void OnDepartmentAddedEvent() { if (DepartmentAddedEvent != null) DepartmentAddedEvent( departmentPresenter.CreateDepartment());
} |
Presenter:
C#-Quelltext 1: 2: 3: 4: 5:
| public DEPARTMENT CreateDepartment() { DEPARTMENT department = new DEPARTMENT(); return department; } |
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 02.12.08 21:46
Zitat: |
es muss doch nicht sein bzw. darf nicht, dass die View in Berührung kommt mit dem Model,
|
Dann fällst du auf die in einem vorherigen Post angesprochene Variante A.) Passive View zurück.
Den Zugriff von View auf Model(nur zum Databinding nicht für Logik) und Presenter halte ich für eine nur kleine Sünde die man wegen des dadurch reduzierten Aufwands eingehen sollte. Wie schonmal gesagt ein Pattern ist nur ein Muster und keine absolutistische Bauanleitung der man nach Gedeih und Verderb folgen muß. Letztlich läuft es aber darauf hinaus ein für deinen Anwendungsfall ein in Umfang angemessenes System aufzustellen.
Ich persönlich (macht aber nur in wirklich großen Anwendungen sind) benutze zurzeit ein MVVMP (Model-View-ViewModel-Presenter) System. Heißt ich habe zwei komplette Datenmodelle eins zwischen Daten - und Business Schicht, das Domainmodel. Sowie eins zwischen Business - und UI Schicht das ApplicationModel. Zwischen diesen beiden Model wird dann in der Businessschicht translatiert (und dabei eben Businesslogik angewendet). Somit hat in diesem Fall der View auch nie Zugriff auf das eigentliche Modell und ist davon entkoppelt.
Zitat: | Nur die zusammengeschusterten blog links tuns irgendwie nicht |
Dann probier vielleicht mal mit den bereits reichlich vorhandenen MVP Frameworks rum und lies deren Doku.
CompositeWPF(ist OpenSource und von Microsoft) scheint übrigens sehr empfehlenswert zu sein.
CompositeWPF - www.codeplex.com/CompositeWPF
Spring.Net - springframework.net/
SCSF/CAB - www.codeplex.com/smartclient
|
|
Nally 
      
Beiträge: 46
|
Verfasst: Di 02.12.08 22:38
1.) Könntest du mir noch zu meinem letzten code posting sagen ob das ok so war?
2.) Sollte man bei MVP alle Methoden in das View interface einbauen und anschließend in der View implementieren, die auf die View zugreifen?
3.) Datenaustausch zwischen 2 Klassen (view+presenter) geht das nur über deinen Beispielcode sprich eigene Klasse oder gehts auch einfacher?:
C#-Quelltext 1:
| public class EventArgs<T> : EventArgs |
Habe mir bereits das mvc# framework angeschaut, doch auch das war mir irgendwie zuviel overhead bzw. das Beispiel ist nicht übertragbar auf meinen Bedarf.
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 03.12.08 00:08
zu 1.)
C#-Quelltext 1: 2: 3: 4: 5: 6: 7:
| private void OnDepartmentAddedEvent() { if (DepartmentAddedEvent != null) DepartmentAddedEvent( departmentPresenter.CreateDepartment());
} |
Das sieht in der Tat merkwürdig aus. Da habe ich dich mit meinem Event Geschwaffel wohl aufs Glatteis geführt
Der Event wird ja wahrscheinlich vom Presenter gefangen es lohnt sich sicher nicht ein Objekt dorthin zu übergeben das auch vom Presenter erzeugt wird. CreateDepartment kann der Presenter dann doch selbst in seinem Event aufrufen. In diesem Beispiel würde ein EventHandler ohne Parameter also besser passen.
zu 2.) Ja. Alles was öffentlich ist gehört auch in ein Interface
zu 3.) Nein. Beim Design des Delegaten ist man frei und kann es im Prinzip machen wie man will. Ich mache es oft wie gezeigt weil es dem Standard EventHandler entspricht somit eine eindeutige Signatur hat (eben Sender plus EventArgs) und damit wieder durch ein weiteres Pattern(?) einen EventBroker automatisch verdrahtet werden können(Der Grund ist also für dich eher uninteressant). Und zweitens weil in den meisten Fällen genau 1 Datenobjekt in einem Event übergeben wird, eben genau das Objekt auf den der Event wirkt, und mein obiger Ansatz immer funktioniert ohne das ich jedesmal einen neuen Delegaten definieren muß. So wie gezeigt macht man das nur einmal und kann es dann überall nach belieben benutzen.
|
|
Nally 
      
Beiträge: 46
|
Verfasst: Mi 03.12.08 15:27
warum ist deine Presenter Klasse partial? Ist mir erst jetzt aufgefallen. Sollte ja nicht sein... oder war das ein Typo von dir?
und das einfache hinzufügen meiner Entität an die datasource der bindingsource funktioniert natürlich nicht, denn dann wird ja nur die gerade erzeugte entität bzw. das neue Department in der Listbox angezeigt. ALSO muss ich meinen context nochmals abfragen... hab mir eh schon überlegt den context in ein singleton zu packen für irgendwas muss das Muster ja mal gebraucht werden ^^
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 03.12.08 16:15
Zitat: | warum ist deine Presenter Klasse partial? Ist mir erst jetzt aufgefallen. Sollte ja nicht sein... oder war das ein Typo von dir? |
Richtig in dem Fall überflüssig, war ein Copy&Paste Fehler.
Zitat: |
und das einfache hinzufügen meiner Entität an die datasource der bindingsource funktioniert natürlich nicht, denn dann wird ja nur die gerade erzeugte entität bzw. das neue Department in der Listbox angezeigt. ALSO muss ich meinen context nochmals abfragen... hab mir eh schon überlegt den context in ein singleton zu packen für irgendwas muss das Muster ja mal gebraucht werden ^^ |
Auch eine Liste von Entitäten ist ein Entität. Wenn dein View eine Liste von Objekten darstellt so würde ich zwischen View und Presenter die Liste austauschen. Also Liste an Presenter übergeben neues Element hinzufügen und dann geänderte Liste wieder an View binden. Der View selber sollte nicht selbst die Liste bearbeiten, das ist nicht sein Job.
|
|
Nally 
      
Beiträge: 46
|
Verfasst: Sa 06.12.08 17:44
so hatte mal etwas Zeit wieder...
Habe das ganze mal so umgemodelt, dass es für mich verständlich und erweiterbar ist.
Was hälst du von dem Konstrukt?
VIEW:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| public partial class MainWindowView : Form , IDepartmentView { private IDepartmentPresenter departmentPresenter; public event PassViewDepartmentDataHandler PassViewDepartmentData;
public MainWindowView() { InitializeComponent(); departmentPresenter = new DepartmentPresenter(this); }
public void DataToBindingSource(ObjectQuery queryDepartment) { dEPARTMENTBindingSource.DataSource = queryDepartment; }
private void addDepartmentButton_Click_1(object sender, EventArgs e) { if (PassViewDepartmentData != null) PassViewDepartmentData(departmentTextBox.Text); } } |
PRESENTER:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| class DepartmentPresenter : IDepartmentPresenter { private IDepartmentView view; private ObjectQuery<DEPARTMENT> queryDepartment;
private CompanyEntities mycontext = new CompanyEntities();
public DepartmentPresenter(IDepartmentView view) { LoadDepartments();
this.view = view; view.PassViewDepartmentData += View_AddDepartment; }
private void LoadDepartments() { try { using (CompanyEntities context = new CompanyEntities()) { queryDepartment = mycontext.DEPARTMENT; } } catch (Exception ex) { Console.WriteLine("Error: " + ex.StackTrace); } view.DataToBindingSource(queryDepartment); }
private void View_AddDepartment(String departmentName) { DEPARTMENT department = new DEPARTMENT();
try { using (CompanyEntities context = new CompanyEntities()) { department.department_name = departmentName; context.AddToDEPARTMENT(department); context.SaveChanges(); } } catch (Exception ex) { Console.WriteLine("Error: " + ex.StackTrace); MessageBox.Show("Die Abteilung: " + departmentName + " existiert bereits", "Fehler!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } queryDepartment.Execute(MergeOption.AppendOnly); view.DataToBindingSource(queryDepartment); } } |
INTERFACE VIEW:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| namespace Company { public delegate void PassViewDepartmentDataHandler(String departmentName);
public interface IDepartmentView { event PassViewDepartmentDataHandler PassViewDepartmentData; void DataToBindingSource(ObjectQuery queryDepartment); } } |
|
|
|