C# von einer Klasse aus Textboxen und weiteres von mehreren Formen ändern

HorusIX

Cadet 1st Year
Registriert
Dez. 2018
Beiträge
9
Hallo liebes Forum, ich programmiere ungafähr seit paar Monaten mit C#. Ich erstelle seit heute eine Ballsportverwaltung. Ich will dies mit dem Drei-Schichten-Modell bestreben. Nun stell ich mit die Frage wie ich mit der Klasse "Verwaltung" auf meine beiden Form's zugreifen kann...
Kann mir da jemand helfen?

Danke im voraus, Julius.
 
Hallo Julius,

um Dir überhaupt helfen zu können poste doch zumindest Teile der Klassen (hier vor allem Übergabeparameter + Methoden) die du benutzen möchtest.

Prinzipiell gehst Du das aber falsch an, das View-Model sollte nicht auf die Model-View zugreifen. Versuche es anders zu sehen, deine Forms (Views) geben Daten in Richtung des ViewModels (z.B. Managerklassen) und diese wiederrum nutzen dann die Models (deine Klasse Verwaltung).

Gruss
SchiBuh
 
Gar nicht. Die Business-Schicht hat nix an der UI-Schicht verloren.

Es gibt natürlich mehrere Wege, aber ein möglicher ist:

Die Business-Schicht gibt dir ein Datenobjekt, das kapselst du in einem ViewModel (darin bereitest du die Daten für die UI auf, z.B. Zahlen wie 0.19 in "19%" formatieren). An der UI werden diese ganz stupide angezeigt (die UI hat im Idealfall bis auf das Binden, Animationen etc. 0 Code). Die UI hat Events, z.B. für ein Klick, diese nutzt du um im ViewModel eine Methode wie "DeleteClicked" aufzurufen. Das ViewModel wandelt das Event dann in die nötige Struktur für die Business-Schicht um und ruft sie damit auf.
 
  • Gefällt mir
Reaktionen: hroessler
@Bagbag hat recht. Die 3 Schichten sollten nichts voneinder wissen. Die Kommunikation sollte entweder per Events (definiert in einem Interface!) oder noch besser per Dependency Injection stattfinden.

Einfach mal Google anwerfen :)

greetz
hroessler
 
Form2:

C#:
namespace Ballsportturnier
{
    public partial class Form2 : Form
    {
        private Verwaltung dieVerwaltung;

        internal Form2(Verwaltung dieVerwaltung)
        {
            this.dieVerwaltung = dieVerwaltung;
            InitializeComponent();
        }

Form1:
C#:
namespace Ballsportturnier
{
    public partial class Form1 : Form
    {
        Verwaltung dieVerwaltung;
        private Form2 Frm2;
        public Form1()
        {
            InitializeComponent();
            dieVerwaltung = new Verwaltung(this);
            Frm2 = new Form2(dieVerwaltung);
        }

klasse Verwaltung:



C#:
namespace Ballsportturnier

{

    class Verwaltung

    {

        Form1 dieGUI;


        public Verwaltung(Form1 pForm)

        {

            dieGUI = pForm;

        }
 
Sofern du nicht auf Windows Forms angewiesen bist würde ich auf WPF umsteigen. Aktueller und mMn auch verständlicher machbar wenn man sich dran gewöhnt hat.
Dann käme ungefähr sowas zustande:
C#:
(MyView.xaml.cs)
public partial class MyView : Window
{
    public MyView(){
        InitializeComponent();
   
        DataContext = new MyViewModel();    // könnte auch in der XAML stehen
    }
}

(MyViewModel.cs)
public class MyViewModel
{
    public MyViewModel(){
        // Initialisierung oder so
    }
   
    // Kommando Reaktionen aus der View regeln über Implementierung von ICommand durch Properties
}

(MyModel.cs)
public class MyModel
{
    // Was auch immer du für Datenobjekte brauchst, das sind deine Models/Klassen
    // Datenhaltung, etc.
}

In der View.xaml wird das dann an die entsprechenden Eigenschaften gebunden, wie zum Beispiel eine Text-Property a la public string MyText { get; set; } an einen Textblock: <Textblock Text={Binding MyText} />

Soll das bei jeder Änderung geupdated werden musst du noch das Interface INotifyPropertyChanged im ViewModel und je nach Struktur in den Models implementieren. Für Kommandos habe ich mir eine generelle Command Klasse implementiert mit einer Execute und einer CanExecute Methode, wobei erstere die auszuführende Logik beim aktivieren des Kommandos beschreibt und letztere ob das Kommando überhaupt ausgeführt werden darf (Rückgabewert Boolean). Das kann man dann zum Beispiel an jeden beliebigen Button dranhängen:
XML:
<Button Command={Binding MyBtnCommand}/>
C#:
(ViewModel)
public Command MyBtnCommand{ get; set; }
...
MyBtnCommand = new Command(ExecBtnLogic, CanExecBtnLogic);
...
private void ExecBtnLogic(){
    // blabla
}
private bool CanExecBtnLogic(){
    return bedingung1 && bedingung2;
}

Über diese Commands kann man dann auch einfach eine neue View öffnen, wenn ein bestimmter Button geklickt wird usw.
 
Wenn du bei Forms bleiben willst (wofür es durchaus einige Gründe gibt):
Zieh deine Schichtentrennung durch. Wenn du in deinem Form eine Instanz zur Logikschicht erstellst und dieser eine Referenz zu deinem Form mit gibst, hast du die Trennung bereits in die Tonne gehauen.
Deine "Verwaltung" sollte hingegen alle Möglichkeiten bereitstellen, die dein UI benötigt. Im UI rufst du dann die Methoden der Verwaltung auf. So bekommst du auch keine Probleme, zurück in das UI zu schreiben (du bekommst ja ganz einfach Rückgabewerte von der Verwaltung) und kannst z.B. sehr einfach async implementieren. Wenn du callbacks für einen Fortschrittsbalken brauchst, schau dir mal die Klasse Progress bzw. IProgress an - alles schon fertig.
Es geht also von oben nach unten, wobei der "untere" den "oberen" überhaupt nicht kennt.
UI ruft Logik auf, Logik ruft Datenschicht auf.
 
  • Gefällt mir
Reaktionen: Nero1
@Nero1 Ja, ich bin auf Windows Forms angewiesen.
@Enurian
Meinst du etwa wie bei diesem Beispiel?
C#:
 public void einstellungenSpeichern(int pAnzahlMannschaften, char pTyp)
        {
            anzahlMannschaften = pAnzahlMannschaften;
            regelTyp = pTyp;
 
@HorusIX "EinstellungenSpeichern" mit entsprechenden Parametern was zu speichern ist wäre eine typische Methode für die Verwaltung / Logik, ja. Statt void könnte man auch einen bool o.ä. zurückgeben, um am UI dann anzeigen zu können, ob das speichern erfolgreich war oder nicht. So brauchst du in der EinstellungenSpeichern-Methode selbst keinen Zugriff auf UI Elemente.
 
@Enurian danke. Ich hätte noch eine Frag zu einem Fehler der grad bei mir auftritt:
System.FormatException
HResult=0x80131537
Nachricht = Die Eingabezeichenfolge hat das falsche Format.
Quelle = mscorlib
Stapelüberwachung:
bei System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
bei System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
bei System.Convert.ToInt32(String value)

C#:
case 3:
                    if (Convert.ToInt32(dieGUI.lab0Par1.Text) > Convert.ToInt32(dieGUI.lab0Par2.Text))
                    {
                        mann1punkte = mann1punkte + punkteS;
                        mann1plus = mann1plus + Convert.ToInt32(dieGUI.lab0Par1.Text);
                        mann1minus = mann1minus + Convert.ToInt32(dieGUI.lab0Par2.Text);

                        mann0punkte = mann0punkte + punkteN;
                        mann0plus = mann0plus + Convert.ToInt32(dieGUI.lab0Par2.Text);
                        mann0minus = mann0minus + Convert.ToInt32(dieGUI.lab0Par1.Text);

                    }
                    else
                    {
                        if (Convert.ToInt32(dieGUI.lab0Par1.Text) < Convert.ToInt32(dieGUI.lab0Par2.Text))
                        {
                            mann0punkte = mann0punkte + punkteS;
                            mann0plus = mann0plus + Convert.ToInt32(dieGUI.lab0Par2.Text);
                            mann0minus = mann0minus + Convert.ToInt32(dieGUI.lab0Par1.Text);

                            mann1punkte = mann1punkte + punkteN;
                            mann1plus = mann1plus + Convert.ToInt32(dieGUI.lab0Par1.Text);
                            mann1minus = mann1minus + Convert.ToInt32(dieGUI.lab0Par2.Text);
                        }
                        else
                        {
                            mann0punkte = mann0punkte + punkteU;
                            mann0plus = mann0plus + Convert.ToInt32(dieGUI.lab0Par2.Text);
                            mann0minus = mann0minus + Convert.ToInt32(dieGUI.lab0Par1.Text);

                            mann1punkte = mann1punkte + punkteU;
                            mann1plus = mann1plus + Convert.ToInt32(dieGUI.lab0Par1.Text);
                            mann1minus = mann1minus + Convert.ToInt32(dieGUI.lab0Par2.Text);
                        }
                    }
 
Zuletzt bearbeitet:
Steht doch alles da: du versuchst einen Text in eine Zahl umzuwandeln, der keine Zahl bzw. falsch formatiert ist.
Um welche Zeile mit welchen Werten es sich handelt, bekommst du ganz einfach mit dem Debugger raus.
 
@Enurian, ja das seh ich auch aber ich hab die ganzen variablen als int festgelegt:
C#:
 int mann1punkte = 0;
            int mann2punkte = 0;
            int mann3punkte = 0;
            int mann4punkte = 0;
            int mann5punkte = 0;
            int mann0punkte = 0;
            int mann1minus = 0;
            int mann2minus = 0;
            int mann3minus = 0;
            int mann4minus = 0;
            int mann5minus = 0;
            int mann0minus = 0;
            int mann1plus = 0;
            int mann2plus = 0;
            int mann3plus = 0;
            int mann4plus = 0;
            int mann5plus = 0;
            int mann0plus = 0;

Und deswegen weis ich nicht was da falsch sein sol?!
Ergänzung ()

Unbenannt.PNG
 
Zuletzt bearbeitet:
Du solltest dir vielleicht mal ansehen wie es ist mit Listen und Arrays zu arbeiten.
Bei dem Programmierstil bekommt man ja Schreikrämpfe :D
 
Schau dir mal an, was in dieGUI.lab6Par1.Text und dieGUI.lab6Par2.Text drin steht (bspw. mit dem Debugger, während die Exception fliegt), und überleg dir, warum das nicht in ein int konvertiert werden kann.

PS: beherzige ratzeputz Ratschlag.
PPS: Ich habe keine Ahnung wofür lab6Par1 stehen könnte (damit will ich sagen, dass die Variablennamen verbesserungsfähig sind).
 
Ok, Danke ich versuchs mal
Doch jetzt kommt wieder der allbekannte Fehler:
FORM2:
C#:
private void btErgebnisseZusammenfassen_Click(object sender, EventArgs e)
        {
            dieVerwaltung.ergebnisseZusammenfassen();

            tabControl1.SelectedIndex = 3;
        }
Klasse "Verwaltung":
C#:
public void ergebnisseZusammenfassen()
        {
            for (int i = 0; i < 5; i++)
            {
                dieMannschaft[i].setzePunkte(0);
                dieMannschaft[i].setzeToreMinus(0);
                dieMannschaft[i].setzeTorePlus(0);
            }

           switch(anzahlMannschaften)
            {
                case 3:
                    if (Convert.ToInt32(dieGUI.tb1Par0.Text) > Convert.ToInt32(dieGUI.tb2Par0.Text))
                    {
                        dieMannschaft[1].setzePunkte(dieMannschaft[1].gibPunkte() + punkteS);
                        dieMannschaft[1].setzeTorePlus(dieMannschaft[1].gibTorePlus() + Convert.ToInt32(dieGUI.tb1Par0.Text));
                        dieMannschaft[1].setzeToreMinus(dieMannschaft[1].gibToreMinus() + Convert.ToInt32(dieGUI.tb2Par0.Text));
                        dieMannschaft[0].setzePunkte(dieMannschaft[0].gibPunkte() + punkteN);
                        dieMannschaft[0].setzeTorePlus(dieMannschaft[0].gibTorePlus() + Convert.ToInt32(dieGUI.tb2Par0.Text));
                        dieMannschaft[0].setzeToreMinus(dieMannschaft[0].gibToreMinus() + Convert.ToInt32(dieGUI.tb1Par0.Text));
                    }
                    else
                    {
                        if (Convert.ToInt32(dieGUI.tb1Par0.Text) < Convert.ToInt32(dieGUI.tb2Par0.Text))
                        {
                            dieMannschaft[1].setzePunkte(dieMannschaft[1].gibPunkte() + punkteN);
                            dieMannschaft[1].setzeTorePlus(dieMannschaft[1].gibTorePlus() + Convert.ToInt32(dieGUI.tb1Par0.Text));
                            dieMannschaft[1].setzeToreMinus(dieMannschaft[1].gibToreMinus() + Convert.ToInt32(dieGUI.tb2Par0.Text));
                            dieMannschaft[0].setzePunkte(dieMannschaft[0].gibPunkte() + punkteS);
                            dieMannschaft[0].setzeTorePlus(dieMannschaft[0].gibTorePlus() + Convert.ToInt32(dieGUI.tb2Par0.Text));
                            dieMannschaft[0].setzeToreMinus(dieMannschaft[0].gibToreMinus() + Convert.ToInt32(dieGUI.tb1Par0.Text));
                        }
                        else
                        {
                            dieMannschaft[1].setzePunkte(dieMannschaft[1].gibPunkte() + punkteU);
                            dieMannschaft[1].setzeTorePlus(dieMannschaft[1].gibTorePlus() + Convert.ToInt32(dieGUI.tb1Par0.Text));
                            dieMannschaft[1].setzeToreMinus(dieMannschaft[1].gibToreMinus() + Convert.ToInt32(dieGUI.tb2Par0.Text));
                            dieMannschaft[0].setzePunkte(dieMannschaft[0].gibPunkte() + punkteU);
                            dieMannschaft[0].setzeTorePlus(dieMannschaft[0].gibTorePlus() + Convert.ToInt32(dieGUI.tb2Par0.Text));
                            dieMannschaft[0].setzeToreMinus(dieMannschaft[0].gibToreMinus() + Convert.ToInt32(dieGUI.tb1Par0.Text));
                        }
                    }
...
Entwurf:
Unbenannt.PNG

Dabei sind die abgebildeten Textboxen die tb(zeile)Par(1=links/2=rechts)

Der Fehler:
Unbenannt1.PNG
 
Zuletzt bearbeitet:
Und was für Probleme hast du mit dem "allbekannten Fehler"? Die Fehlermeldung ist doch eindeutig.
 
Ja, das ist mir auch klar, dass da keine null stehen darf, aber ich muss da ne null stehen haben sonst klappt des net.
 
null ist etwas ganz anderes als 0.
 
Es geht nicht um die 0 in setzePunkte(0). Du hast "dieMannschaft" nie initialisiert, d.h. die Variable hat den Wert null.
 
So dann, oder wie?
Ergänzung ()

Unbenannt.PNG

jetzt hab ich den nächsten Fehler... :( anzahlMannschaften ist 3 also weis ich mal wieder nicht was da los ist
 
Zuletzt bearbeitet:
Zurück
Oben