Announcement

Collapse
No announcement yet.

ComboBoxen, TextBoxen, TabPages, DateTimePicker

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • ComboBoxen, TextBoxen, TabPages, DateTimePicker

    Hallo Andreas und alle zusammen,
    ich habe ein paar (wahrscheinlich Anfänger-)Probleme mit den oben genannten Controls. Ich habe eine Forms, die über ein BindingContext mit einem DataSet verbunden ist.

    1. TabPages:
    In der Forms gibt es 2 über Registerkarten anwählbaren TabPages und ich möchte gerne beim Aufruf der Forms in bestimmten Fällen gleich die TabPage2 anzeigen - ist mir bisher noch nicht gelungen. Welche Methode oder welches Event führt mich direkt auf eine gewünschte TabPage?

    2. TextBox:
    Ich habe eine TextBox, die nicht zwingend mit Werten gefüllt sein muß. Wenn ich dort einen Wert vorfinde (vom DataSet geladen oder selbst eingetragen) und ihn manuell löschen möchte, funktioniert das nicht, d.h. der alte Wert erscheint, sobald ich das Control verlasse immer wieder. Wenn ich den Wert ändere (nicht lösche!), wird das akzeptiert. Was muß ich tun, damit auch ein Löschen akzeptiert wird? Muß ich ein Event behandeln und dort explizit DBNull zuweisen?

    3. ComboBox:
    Ich habe mehrere ComboBoxen im "DropDownList"-Style. Über ein Mapping hole ich mir die zugrundeliegende Liste aus einer speziellen Mapping-Tabelle. Klappt auch alles gut, aber sobald ich einen neuen Satz anlege, bei dem ja alle Werte noch Null sein müßten, wird in allen ComboBoxen der Wert angezeigt, der zum kleinsten Index der zugehörigen Mapping-Liste gehört.
    Ich will aber noch gar keine Auswahl anzeigen, das Feld soll erst mal leer bleiben. geht das irgendwie? Muß ich extra einen Listen-Eintrag mit einem Null-Wert in der Mapping-Tabelle anlegen?

    4. DateTimePicker
    Mir ist es noch nicht gelungen, auf ein DateTimePicker-Element einen Null-Wert zu legen (wäre für den gleichen Fall, wie bei Punkt 3. beschrieben, nötig, nämlich für einen neu angelegten Satz).

    Vielen Dank für Eure Hilfe
    Rolf

  • #2
    Hallo Rolf,

    für Punkt 4.) hätte ich evtl. eine Lösung:

    <I>DateTimePicker</I> hat eine Eigenschaft <I>ShowCheckBox</I> mit der im <I>DateTimePicker</I> eine kleine CheckBox angezeigt wird. Sobald diese Eigenschaft den Wert <I>true</I> hat, läßt sich die CheckBox über die Eigenschaft <I>Checked</I> (<I>True</I> bzw. <I>False</I>) steuern.
    Wenn <I>Checked</I> den Wert <I>False</I> zugewiesen bekommt, ist der <I>DateTimePicker</I> disabled und zeigt "keinen" Datums-Wert an. D.h. bei Dir würde bei einem <I>DBNull</I>-Wert des Datenbankfeldes einfach <I>Checked</I> auf <I>false</I> gesetzt und der Anwender kann es je nach belieben wieder auf <I>true</I> setzen und das Datumsfeld editieren.

    Die Lösung ist zwar etwas umständlich, aber ich habe sie bis jetzt sehr gut einsetzen können...

    hoffe ich konnte Dir weiterhelfen

    christia

    Comment


    • #3
      Hallo,

      zu 1. TabPages: <br>
      Dafür ist die TabControl-Eigenschaft <b>SelectedTab</b> zuständig:
      <pre>
      private void Form1_Load(object sender, System.EventArgs e)
      {
      this.tabControl1.SelectedTab = this.tabPage2;
      }
      </pre>

      zu 2. TextBox leeren:<br>
      Wie das folgende Beispiel zeigt, ist das kein generelles Problem, solange das Entfernen der Eingabe nicht mit dem dahinterliegenden Datenbank-Schema (NULL vs. NOT NULL) kollidiert. Beim folgenden Beispiel kann das Alter aus der 3. TextBox problemlos entfernt werden:
      <pre>
      private DataTable aNewDataTable;

      private void button1_Click(object sender, System.EventArgs e)
      {
      // neue DataTable erzeugen
      aNewDataTable = new DataTable();
      aNewDataTable.Columns.Add("Nachname", typeof(String));
      aNewDataTable.Columns.Add("Vorname", typeof(String));
      aNewDataTable.Columns.Add("Alter", typeof(String));
      aNewDataTable.PrimaryKey = new DataColumn[] {aNewDataTable.Columns["Nachname"], aNewDataTable.Columns["Vorname"]};
      // neuen Datensatz eintragen
      DataRow aNewRow;
      aNewRow = aNewDataTable.NewRow();
      aNewRow[0] = "Kosch";
      aNewRow[1] = "Andreas";
      aNewRow[2] = "40";
      // neuen Datensatz eintragen
      aNewDataTable.Rows.Add(aNewRow);
      aNewRow = aNewDataTable.NewRow();
      aNewRow[0] = "Mustermann";
      aNewRow[1] = "Manfred";
      aNewRow[2] = "42";
      aNewDataTable.Rows.Add(aNewRow);
      // Ergebnis anzeigen
      textBox1.DataBindings.Add("Text", aNewDataTable, "Nachname");
      textBox2.DataBindings.Add("Text", aNewDataTable, "Vorname");
      textBox3.DataBindings.Add("Text", aNewDataTable, "Alter");
      }

      private void button2_Click(object sender, System.EventArgs e)
      {
      this.BindingContext[aNewDataTable].Position += 1;
      }

      private void button3_Click(object sender, System.EventArgs e)
      {
      this.BindingContext[aNewDataTable].Position -= 1;
      }
      </pre>
      Wird der Datentyp der Spalte "Alter" allerdings von string auf <b>Int32</b> geändert, so ignoriert .NET das Leeren der TextBox. Um diesen Effekt zu vermeiden, muss das Programm selbst klare Verhältnisse schaffen. Das könnte zum Beispiel so aussehen (System.DBNull.Value):
      <pre>
      private DataTable aNewDataTable;

      private void OnAlterParse(object sender, ConvertEventArgs e)
      {
      if ((string)e.Value == "")
      {
      e.Value = System.DBNull.Value;
      }
      }

      private void button1_Click(object sender, System.EventArgs e)
      {
      // neue DataTable erzeugen
      aNewDataTable = new DataTable();
      aNewDataTable.Columns.Add("Nachname", typeof(String));
      aNewDataTable.Columns.Add("Vorname", typeof(String));
      aNewDataTable.Columns.Add("Alter", typeof(Int32));
      aNewDataTable.PrimaryKey = new DataColumn[] {aNewDataTable.Columns["Nachname"], aNewDataTable.Columns["Vorname"]};
      // neuen Datensatz eintragen
      DataRow aNewRow;
      aNewRow = aNewDataTable.NewRow();
      aNewRow[0] = "Kosch";
      aNewRow[1] = "Andreas";
      aNewRow[2] = 40;
      // neuen Datensatz eintragen
      aNewDataTable.Rows.Add(aNewRow);
      aNewRow = aNewDataTable.NewRow();
      aNewRow[0] = "Mustermann";
      aNewRow[1] = "Manfred";
      aNewRow[2] = 42;
      aNewDataTable.Rows.Add(aNewRow);
      // Ergebnis anzeigen
      textBox1.DataBindings.Add("Text", aNewDataTable, "Nachname");
      textBox2.DataBindings.Add("Text", aNewDataTable, "Vorname");
      Binding aB = new Binding("Text", aNewDataTable, "Alter");
      aB.Parse += new ConvertEventHandler(this.OnAlterParse);
      textBox3.DataBindings.Add(aB);
      }

      private void button2_Click(object sender, System.EventArgs e)
      {
      this.BindingContext[aNewDataTable].Position += 1;
      }

      private void button3_Click(object sender, System.EventArgs e)
      {
      this.BindingContext[aNewDataTable].Position -= 1;
      }
      </pre>

      zu 3. ComboBox: <br>
      Die Frage ist, ob die Tabellenspalten einen NULL-Wert zulässt oder nicht. Wenn ja, muss dieser Zustand auch über die ComboBox ausgewählt werden können. Wenn nein, ist die "Vorbelegung" irrelevant, da der Anwender selbst den richtigen Wert zwingend auswählen muss.

      zu 4. DateTimePicker: <br>
      Das DataTimePicker-Controll kann keine DBNull-Werte darstellen/verarbeiten. Es gibt somit meines Wissens nach nur 2 zusätzliche Optionen (wobei die im vorherigen Beitrag genannte Option besser ist): <br>
      1. Control nur indirekt für die Auswahl eines Datums nutzen/einblenden <br>
      2. Eigenes Default-Datum (Dummy-Datum) definieren und über die Ereignisse <b>Format</b> und <b>Parse</b> verwarbeiten.

      Die Binding-Objekte stellen die Ereignisse <b>Format</b> und <b>Parse</b> zur Verfügung, um die Darstellung der Daten in der
      Benutzeroberfläche anpassen zu können. Das Format-Ereignis wird immer dann ausgelöst, wenn die Daten von der Datenquelle zum Control durchgereicht werden, bzw. auch in der Gegenrichtung vom Control zur Datenquelle. Für den Fall, dass der Anwender seine Eingabe in einem bestimmten Format vornimmt, stellt das Parse-Event die Option zur Verfügung, die Eingabe zuerst in das notwendige Datenformat zurückzutransformieren.
      <pre>
      private void OnFormat(object sender, System.Windows.Forms.ConvertEventArgs e)
      {
      if (e.Value == System.DBNull.Value)
      {
      e.Value = DateTime.Parse ("1.1.1800");
      }
      }

      private void OnParse(object sender, ConvertEventArgs e)
      {
      if ((DateTime)e.Value == DateTime.Parse ("1.1.1800"))
      {
      e.Value = System.DBNull.Value;
      }
      }

      private void button1_Click_1(object sender, System.EventArgs e)
      {
      string sCS = "data source=localhost;initial catalog=Northwind;integrated security=SSPI";
      SqlConnection aCon = new SqlConnection(sCS);
      SqlCommand aCmd = new SqlCommand("SELECT OrderDate FROM Orders", aCon);
      SqlDataAdapter aAdp = new SqlDataAdapter(aCmd);
      DataSet aDS = new DataSet();
      aAdp.Fill(aDS);
      Binding aB = new Binding("Text", aDS.Tables[0], "OrderDate");
      aB.Format += new ConvertEventHandler(this.OnFormat);
      aB.Parse += new ConvertEventHandler(this.OnParse);
      textBox1.DataBindings.Add(aB);
      }
      </pre>
      &#10

      Comment


      • #4
        Hallo Andreas und Christian und alle zusammen,

        vielen Dank für Eure Tipps! Mein Problem mit dem Löschen eines TextBox-Inhalts ist nun super gelöst, auch das gezielte Anspringen der TabPages klappt, mit allen daranhängenden Bindings.
        Über die ComboBoxen und eine "Leer"-Darstellung muß ich noch nachdenken und das DateTimePicker-Problem will ich morgen angehen.
        Aber ich bin heute noch auf ein kleines anderes Problem gestoßen, vielleicht könnt Ihr mir helfen:
        Ich habe eine TreeView mit mehreren "Haupt"-Nodes, die wiederum Childs haben. Jeder Haupt-Node steht in meiner Anwendung für ein "Projekt". Hinter jedem Child-Node liegen Forms, in denen Daten geändert werden können. Es soll nun folgendes passieren: Falls ich das Projekt wechsele (also einen beliebigen Node eines anderen Projektes anklicke oder expande), sollen automatisch alle bis dahin getätigten Änderungen aus dem DataSet in die Access-DB geschrieben werden. Ich habe jetzt im "AfterSelect"-Event und im "BeforeExpand"-Event eine Update-Methode aufgerufen, die das realisiert. Klappt auch alles ganz gut, nur wenn ein Fehler auftritt, bringt die Methode mir zwar den Fehler, aber ich befinde mich danach schon im neuen Projekt. Ich könnte die Update-Methode im "BeforeSelect"-Event unterbringen, aber wie bekomme ich es hin, dass ich das "fehlerhafte" Projekt nicht verlasse? Es müßte so sein: Anwahl Projekt 1 - Editieren - Wechsel ins andere Projekt, damit Aufruf der Update-Methode - wenn kein Fehler: Sprung ins neue Projekt - im Fehlerfall: "Rücksprung" ins "alte" Projekt. Für dieses Handling ist mir noch keine zündende Idee gekommen, ich habe wahrscheinlich noch nicht das richtige Event gefunden. Und wie muß ich die Exception so werfen, dass das Programm nicht abbricht, aber ich im "alten" Projekt verbleibe? Beim Beenden des gesamten Programms soll auch das automatische Update erfolgen, aber dann darf das Programm natürlich nicht im "alten" Projekt hängenbleiben. Könnt Ihr mir helfen?

        Vielen Dank und viele Grüße von Rol

        Comment

        Working...
        X