C# class Aufrufen

PapstRatze

Lt. Junior Grade
Registriert
Aug. 2008
Beiträge
436
Nach Stundenlangem ausprobieren und gefühlt 1000 nutzlosen Suchen im Internet wende ich mich mal wieder hier an euch, hat ja in der Vergangenheit gut geklappt ;).

Und zwar habe ich ein kleines nettes Programm, das einen Wecker darstellen soll, (es hat keinen sinn, ich will einfach nur lernen ^^) bestehend aus einer Listbox, 3 Textboxen und zugehörigen Buttons.

In die Textboxen gebe ich den Namen des Termin sowie die Stunden und Minuten ein. Mit dem Button wird das ganze gespeichert und der Name in der Listbox gespeichert. Für die Infos habe ich folgende Klasse:

Code:
[COLOR="Blue"]class[/COLOR] [COLOR="Teal"]AlarmTime[/COLOR]
    {
        [COLOR="Blue"]public int[/COLOR] minute;
        [COLOR="blue"]public int[/COLOR] stunde;
        [COLOR="blue"]public string[/COLOR] name;

        [COLOR="blue"]public override string[/COLOR] ToString()
        { 
        [COLOR="blue"]return[/COLOR] name;
        }
    }

Nun will ich wenn ich in der Listbox auf den Namen eines Termins klicke in den Textboxen dessen Daten reinschreiben und dort habe ich keine Ahnung wieso es nicht geht...

Code:
[COLOR="Blue"]private void[/COLOR] listBox1_SelectionChanged([COLOR="blue"]object[/COLOR] sender, SelectionChangedEventArgs e)
        {
[COLOR="SeaGreen"]            // Schaltet den Termin-Löschen Button frei[/COLOR]
            delete_Time.IsEnabled = [COLOR="blue"]true[/COLOR];
            [COLOR="Teal"]AlarmTime[/COLOR] this_time = ([COLOR="teal"]AlarmTime[/COLOR])listBox1.SelectedItem;
                        
            text_name.Text = this_time.name;
            box_minute.Text = this_time.minute.ToString();
            box_stunde.Text = this_time.stunde.ToString();
        }

(der Fehler angezeigte Fehler sagt mir "Das Objekt des Typs "System.String" kann nicht in Typ "window1_1.AlarmTime" umgewandelt werden".)

Jetzt bitte ich um HILFE, wie kann ich this_time zur Ausgewählten klasse machen?

Vielen Dank schonmal für die Antworten, ich weiß sie werden qualifiziert sein :p
 
Zuletzt bearbeitet:
Ohne etwas mehr Code kann ich nur raten... ich würde aber mal tippen, dass listBox1.SelectedItem ein String ist... also kannst du den nicht als AlarmTime casten...


Was genau bindest du denn an deine Listbox?
 
SelectedItem ist ein ListViewItem. Du musst die Daten schon richtig zuordnen, ggf. über den richtigen Konstruktor.
Code:
class AlarmTime
{
  public int minute;
  public int stunde;
  public string name;
  
  public AlarmTime( ListViewItem Item )
  {
    minute = Convert.ToInt32( Item.SubItems[0].Text );
    stunde = Convert.ToInt32( Item.SubItems[1].Text );
    // ...
  }

  public override string ToString()
  { 
    return name;
  }
}
So in etwa.
 
@Yuuri: Die Zeit (stunde & minute) wird beim Einlesen in ein int umgewandelt.

@Mike: So einmal den code beim einlesen:

Code:
private void new_Time_Click(object sender, RoutedEventArgs e)
        {
                AlarmTime newTermin = new AlarmTime();
                newTermin.name = text_name.Text;
                newTermin.minute = int.Parse(box_minute.Text);
                newTermin.stunde = int.Parse(box_stunde.Text);
                listBox1.Items.Add(text_name.Text);
        }

Die Aufgabe ist eine Praktikums Aufgabe meines Profs, die ganze gabs letzte Woche ich gebe mal den Link mit den Aufgaben hier mit: Aufgabe als PDF

Für die Aktivisten die keine Hausaufgaben lösen wollen :p... es gibt in der Regel jede Woche eine neue Aufgabe und ich bin erst in 2 Wochen dran, wollte damit nur schauen ob ich aktuell noch alles verstehe ;)

In der Aufgabe steht man solle eine Funktion "toString" die den Namen wiedergibt einbinden, genau hab ich nicht verstanden wofür, ggf muss es dann heissen:

listBox1.Items.Add(newTermin.toString());

werde es ausprobieren, sobald die Frankfurter "hoffentlich" gewonnen haben :D, jetzt kommt aber erstmal die 2te Hälfte ;)
 
Yuuri schrieb:
SelectedItem ist ein ListViewItem. Du musst die Daten schon richtig zuordnen, ggf. über den richtigen Konstruktor..

Leider ist das falsch. SelectedItem ist vom Typ Object. Und den Ctor von der Datenklasse so anzupassen das er ein GUI-Element entgegen nimmt, halte ich für eine Schlechte Idee dann verlierst du jegliche Art von Wiederverwendbarkeit.

@PapstRatze:Speicher lieber nicht den text_name.Text, sondern speicher das ganze AlarmTime Objekt, dann kannst du den Cast so machen wie es in deinem ersten Post war.
Da du ja erfolgreich -ToString() überschrieben hast, wirst du auch den korrekten AlarmTime Namen angezeigt bekommen in deiner ListBox.
 
Hm, hab mich vorhin geirrt, bin von einem ListView ausgegangen.

Der Absatz mit dem Anklicken der ListBox ist übrigens falsch, denn du bekommst lediglich den Namen zurück, nicht aber die Daten.

Eine ListBox enthält nur Strings, im Feld Items. Die Daten musst du separat in einer Liste von z.B. System.Collections.Generic.List<AlarmTime> oder einem Array (umständlicher und unsauber) festhalten. Beim Ändern der Daten musst du diese im jeweiligen Index abspeichern und beim Wechsel des Index der ListBox musst du das richtige Element wählen und die Controls füllen.
toeffi schrieb:
Leider ist das falsch. SelectedItem ist vom Typ Object. Und den Ctor von der Datenklasse so anzupassen das er ein GUI-Element entgegen nimmt, halte ich für eine Schlechte Idee dann verlierst du jegliche Art von Wiederverwendbarkeit.
Stimmt, ist eine ObjectCollection. Dann wäre das natürlich ohne Probleme möglich und nur durch Casts zu realisieren.
 
Yuuri schrieb:
Eine ListBox enthält nur Strings, im Feld Items. Die Daten musst du separat in einer Liste von z.B. System.Collections.Generic.List<AlarmTime> oder einem Array (umständlicher und unsauber) festhalten. Beim Ändern der Daten musst du diese im jeweiligen Index abspeichern und beim Wechsel des Index der ListBox musst du das richtige Element wählen und die Controls füllen.

Auch das ist nicht richtig :D ListBox hat eine ItemsCollection und da kannst du reinspeichern was du willst :) Und wenn er da ein Item anklickt dann kann er das ohne PRobleme mit SelectedItem abfragen.
 
So wenn ich das richtig verstehe gebe ich der listbox dann AlarmTime und nicht den Namen
in etwa statt:

listBox1.Items.Add(text_name.Text)

listBox1.Items.Add(newTermin)

äähm ich nehme mir jetzt mal die Zeit genauer zu verstehen was Ihr so geschrieben habt und werde es dann auch ausprobieren... (bei Erfolg/Misserfolg melde ich mich dann wieder :D)
 
Du musst nur das eigentliche Objekt hinzufügen, da die ListBox eben Objects aufnimmt.
Code:
// hinzufügen
listBox1.Items.Add( alarmTimeObjekt );

// beim Klicken auf die ListBox
AlarmTime obj = listBox1.SelectedItem as AlarmTime;
Dann kannst du ganz einfach so weiterverfahren. Die Anzeige in der ListBox kommt eben zustande, da du die toString()-Methode überschrieben hast. Sonst würde dort ein "kryptischer" Text stehen wie AlarmTime-Object o.ä.
 
Also, wie ich gesagt habe hat es funktioniert :D... dann bedanke ich mich für die Denkanregung (was fürn wort :D) wenn jemand die Datei oder was ausm Code haben will, kann ich das auch noch gerne hier posten... ich werde mich sicher bald wieder melden ^^ (und ich hab jetzt auch verstanden wieso die funktion toSting drin sein muss)
Ergänzung ()

So und schon wieder habe ich Probleme :D... Das Programm an sich läuft, aber ich bin noch dabei Schwachstellen auszumerzen.

Für die Textboxen habe ich eine Funktion geschrieben, dass beim Klicken in die Textbox der enthaltene Text entfernt wird um dann bequem einen neuen eintippen zu können. Leider stelle ich fest, das bei den Zeit angaben dann ein Fehler auftaucht. Und zwar wenn ich einen Eintrag aus der Liste ausgewählt habe um diesen zu verändern. Obwohl ich über ein statisches bool die Funktion eigentlich eingegrenzt habe geht er erst zu dieser Funktion:

Code:
new_time.stunde = [COLOR="blue"]int[/COLOR].Parse(box_stunde.Text);

in der Textbox steht bei einmaligen klicken natürlich "" (null) damit kann int.Parse nicht umgehen. (im folgenden beide Funktionen die dafür wichtig sind)

Code:
[COLOR="Blue"]private void[/COLOR] box_stunde_IsKeyboardFocusedChanged([COLOR="blue"]object[/COLOR] sender, [COLOR="MediumTurquoise"]DependencyPropertyChangedEventArgs[/COLOR] e)
        {
            counter++;
            [COLOR="blue"]if[/COLOR] (counter % 2 != 0)
            {
                box_stunde.Text = [COLOR="DarkRed"]"0"[/COLOR];
                cleared = [COLOR="blue"]true[/COLOR];
            }
            [COLOR="blue"]else[/COLOR] { cleared = [COLOR="blue"]false[/COLOR];}
            
        }
Code:
[COLOR="blue"]private void[/COLOR] box_stunde_TextChanged([COLOR="blue"]object [/COLOR]sender, [COLOR="MediumTurquoise"]TextChangedEventArgs[/COLOR] e)
        {
            [COLOR="blue"]if[/COLOR] (!cleared)
            {
                [COLOR="blue"]if[/COLOR] (isselected)
                {
                    [COLOR="MediumTurquoise"]AlarmTime[/COLOR] new_time = ([COLOR="MediumTurquoise"]AlarmTime[/COLOR])listBox1.SelectedItem;
                    new_time.stunde = [COLOR="blue"]int[/COLOR].Parse(box_stunde.Text);
                    listBox1.Items.Refresh();
                }
            }
        }

Hier sieht man auch das ich bereits eine Lösung zu dem Problem gefunden habe ... diese finde ich aber sehr unschön. Nächstes Problem ist, dass sich jetzt automatisch die 0 speichert und nicht das was ich danach in die Textbox eingebe. Noch schnell der Vollständigkeit halber, der Code wo isselected herkommt ;)
Code:
[COLOR="blue"]private void[/COLOR] listBox1_SelectionChanged([COLOR="Blue"]object[/COLOR] sender, [COLOR="rgb(72, 209, 204)"]SelectionChangedEventArgs[/COLOR] e)
        {
            
                delete_Time.IsEnabled = [COLOR="blue"]true[/COLOR];
                [COLOR="MediumTurquoise"]AlarmTime[/COLOR] this_time = ([COLOR="MediumTurquoise"]AlarmTime[/COLOR])listBox1.SelectedItem;
            [COLOR="blue"]if[/COLOR](this_time == [COLOR="blue"]null[/COLOR])
            {}
            [COLOR="blue"]else[/COLOR]
            {
                text_name.Text = this_time.name;
                box_minute.Text = this_time.minute.ToString();
                box_stunde.Text = this_time.stunde.ToString();
                isselected = [COLOR="blue"]true[/COLOR];
                
            }
        }

isselected und cleared sind außerhalb der Funktionen als public static bool deklariert.
 
Zuletzt bearbeitet:
Okay, Problem 1 habe ich gelöst, dank der netten Funktion TryParse ;), war dann doch einfacher als gedacht.
Weiß aber leider noch nicht wo der Fehler beim speichern ist
Code:
private void box_minute_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!cleared)
            {
                if (isselected)
                {
                    AlarmTime new_time = (AlarmTime)listBox1.SelectedItem;
                    int.TryParse(box_minute.Text, out minute);
                    [COLOR="Red"]new_time.minute = minute;[/COLOR]
                    listBox1.Items.Refresh();
                }
            }

Vermutlich ist markiertes die Flasche Herangehensweise, nen kleinen Tipp brauch ich noch ;)

#EDIT: Und nochmal Edit: Er ruft die Funktion nur einmal auf, wenn ich in die Box klicke, nicht wenn ich aber etwas rein geschrieben habe... ich glaube ich finde das Problem dann doch selbst :p... muss nur den richtigen Aufruf finden
 
Zuletzt bearbeitet:
Und verräts du uns auch noch den Fehler?:)

In deinem EventHandler listBox1_SelectionChanged solltest du dir mal deine If-Abfrage anschauen die ist so semantische Unsinn, wozu machst du einen leeren If-Block um dann einen else-Block anzuschließen? Warum baust du die If-Abfrage nicht so um, das du gar kein else-Block brauchst ;)

Deine Klasse solltest du auch nochmal überarbeiten die entspricht in keinster Weiße den C# Standards. Öffentliche Felder solltest du vermeiden und dementsprechende Properties mit den enstsprechenden Zugriffsmethode verwenden. Das verbessert deine Klasse in Punkto Sicherheit und Sauberkeit.

Nur private Variablen werden in C# klein geschrieben, deshalbt solltest du deine Properties in deiner Klasse groß schreiben wenn du es jetzt umbaust.

Vielleicht solltest du überlegen anstatt Minuten und Stunden als int zu speichern, ein komplettes DateTime-objekt zu speichern. Dann kannst du auch einen Konstruktor bauen der ein DateTime entgegen nimmt.
 
Und verräts du uns auch noch den Fehler?

ääh welchen ^^... (Ich vermute mal den dessen Lösung int.tryParse war. Naja bei int.Parse hat drei Ausnahmen, eine davon ist, das der string null ist, bei int.tryParse checkt er zuerst ob er den string in ein int umwandeln kann und wenn es möglich ist gibt er per out befehl das int aus... (sehr salopp gesagt ;))

Ja ich gebe dir recht, dass statt:
Code:
if(this_time == null)
            {}
            else
            {
                text_name.Text = this_time.name;
                box_minute.Text = this_time.minute.ToString();
                box_stunde.Text = this_time.stunde.ToString();
                isselected = true;
                
            }
folgendes schöner anzuschauen ist :D
Code:
if(this_time != null)
            {

                text_name.Text = this_time.name;
                box_minute.Text = this_time.minute.ToString();
                box_stunde.Text = this_time.stunde.ToString();
                isselected = true;
             }
Ja das mit den unsauberen Funktionen und Klassen ist mir bewusst und ich gehe Schritt für Schritt, bis das Programm sinnlos aber "glücklich" ist :freak:

Das mit dem DateTime-objekt hört sich nach ner guten Sache an (und auch danach das ich es selbst und zügig hinbekomme)
 
Zurück
Oben