.NET WinForms ComboBox, identische Artikel, und das SelectedIndexChanged-Ereignis

stimmen
5

Es scheint , als wenn Sie eine WinForms .NET - Anwendung haben, und eine ComboBox (auf dem „Drop - Down“ Stil), und dass ComboBox hat darin mehrere Elemente , die identisch sind, seltsame Dinge passieren. Insbesondere kann der Index des ausgewählten Elements ändern , ohne das Ereignis SelectedIndexChanged zu feuern.

Natürlich führt dies zu Massenverwirrung und seltsam, dunkel Fehler, das ist, was ich habe mir die Haare aus über in letzter Zeit ziehen.

Hier ist ein einfaches Beispiel können Sie verwenden, um zu sehen, was ich rede:

  • Machen Sie ein neues .NET WinForms-Projekt (I VB.NET verwenden, aber das Gefühl frei zu übersetzen - es ist einfach genug).
  • Lassen Sie eine ComboBox, einen Knopf, und einen Text (Set Multiline = True) auf das Formular.
  • Verwenden Sie den folgenden Code, um die ComboBox mit 3 identischen Elementen zu laden und einige Statusmeldungen, wenn das SelectedIndexChanged-Ereignis ausgelöst drucken und zu sehen, was der aktuell ausgewählte Index (über einen Button) ist:
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
        TextBox1.Text = TextBox1.Text & vbNewLine & ComboBox SelectedIndexChanged event fired. & vbNewLine & _
            SelectedIndex is:  & ComboBox1.SelectedIndex
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        ComboBox1.Items.Add(John Doe)
        ComboBox1.Items.Add(John Doe)
        ComboBox1.Items.Add(John Doe)

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        TextBox1.Text = TextBox1.Text & vbNewLine & _
        Button clicked. & vbNewLine & _
        SelectedIndex is:  & ComboBox1.SelectedIndex
    End Sub

Führen Sie das Projekt, und wählen Sie ein Element aus der ComboBox (sagen wir, der mittlere). Dann klicken Sie auf den Dropdown-Pfeil des ComboBox-, aber NICHTS SELECT. Klicken Sie auf die Schaltfläche (Button1 standardmäßig) und sehen, was es sagt.

Es sei denn, ich habe meinen Verstand verloren, hier ist was Sie sehen sollten:

ComboBox SelectedIndexChanged-Ereignis ausgelöst.
SelectedIndex: 1
Schaltfläche geklickt.
SelectedIndex ist: 0

Mit anderen Worten hat der ausgewählte Index geändert, aber ohne die SelectedIndexChanged Ereignis Brennen!

Dies geschieht nur, wenn die Elemente in der ComboBox identisch sind. Wenn sie unterschiedlich sind, dann ist dies nicht passieren. (Es kommt vor, auch nicht, wenn die ComboBox „DropDown“ Stil ist auf „Dropdownlist“).

Ich vermute, dass dies einen Fehler in dem .NET-Framework selbst sein kann und nicht etwas, was ich beheben können, aber für den unwahrscheinlichen Fall, dass jemand eine Idee hat, auf das, was hier zu tun (oder was könnte ich tun falsch sein!), Bitte läuten ! Ich bin an einem Verlust dieses Verhalten oder zu arbeiten, um es zu erklären (ich erwarte, dass die SelectedIndex gleich bleiben, es wäre denn, ich weiß schon, Sie tatsächlich ändern, indem Sie etwas andere Auswahl!)

Veröffentlicht am 09/12/2008 um 23:04
quelle vom benutzer
In anderen Sprachen...                            


4 antworten

stimmen
17

Das .NET Framework eigentlich nicht den Überblick über den ausgewählten Index des Tropfens des Kombinationsfelds Down-Liste; dies wird intern von dem Windows-API behandelt. Als Folge davon ist .NET auf dem Windows-API angewiesen, es zu benachrichtigen, wenn die ausgewählten Indexänderungen mittels einer Benachrichtigung an die Fenstergriff Combo Box gesendet, so dass es wiederum das SelectedIndexChanged Ereignis auslösen können.

Leider stellt sich heraus , dass die besondere Benachrichtigung , die .NET Uhren ( um CBN_SELCHANGEgenau zu sein) , in denen nicht alle möglichen Szenarien abdecken könnte der ausgewählte Index ändern. Insbesondere CBN_SELCHANGEwird nur von der Windows - API gesendet , wenn der Benutzer klickt auf oder wählt den Pfeiltasten, ein Element in der Dropdown - Liste. Jedoch in einem Kombinationsfeld Drop - Down - Stil, der Akt das Kombinationsfeld zu öffnen , wird Windows auf dem Text im Bearbeitungsteil des Kombinationsfeldes suchen, durch die Liste der Elemente für ein Spiel suchen, und wenn eine Übereinstimmung gefunden wird, automatisch wählen Sie den entsprechenden Punkt (oder das erste passende Element, wenn es mehrere Übereinstimmungen ergeben ist). Dies kann den ausgewählten Index ändern, aber nicht zu einem schickenCBN_SELCHANGE Benachrichtigung, so vermisst .NET die Tatsache, dass es geändert und Feuer nicht das SelectedIndexChanged-Ereignisses.

Windows tut dies alles in einem Kombinationsfeld Drop-Down-Stil, weil der Benutzer nicht etwas in der Dropdown-Liste hat zu holen; sie können, was sie wollen eingeben. Also jedes Mal, wenn Sie das Kombinationsfeld öffnen wird davon ausgegangen, dass der Benutzer den Text geändert haben und versucht, erneut zu synchronisieren mit dem, was in der Liste, wenn er kann.

In Ihrem Fall, wenn Sie die Combo-Box zum zweiten Mal öffnen, ist es wieder Syncing und das erste Spiel für den Text im Bearbeitungsteil der Auswahl, die „John Doe“ # 0 und Ändern des ausgewählten Index 0 ist ohne .NET sich dessen bewusst.

So ist es im Grunde um einen Fehler in dem .NET Framework. Leider gibt es keine perfekte Abhilfe - Sie können Windows erhalten nicht die Re-Synchronisierung durchführen, und es gibt kein Ereignis, das unmittelbar nach dem Wieder sync feuert, in dem tritt den neuen ausgewählten Index erhalten. (Das Drop-down-Ereignis ausgelöst tatsächlich direkt vor der erneuten Synchronisierung stattfindet, so wird es den neuen Index nicht sehen.) Über das Beste, was Sie tun können, ist das DropDownClosed Ereignis zu behandeln, geht davon aus, dass der Index an diesem Punkt geändert hat, und entsprechend handeln .

Beantwortet am 10/12/2008 um 04:29
quelle vom benutzer

stimmen
2

Erics Antwort war sehr gründlich, aber ich war überrascht zu sehen, dass es nicht mit haben Sie am Ende „... aber wirklich, sollten Sie sie fragen, warum Sie ein Kombinationsfeld mit doppelten Elementen bevölkern.“ Die .NET Framework Fehler kein Zweifel haben, weil erlaubt zu existieren, wenn Sie die Steuerung wie vorgesehen zu verwenden, der Benutzer zu ermöglichen ein Element aus einer Liste auswählen, die Sie nicht in diese Fehler laufen.

Wie wird der Benutzer zwischen den identischen Einträgen unterscheiden? Warum sollten sie übereinander wählen? Gibt es eine andere Bedeutung zu den verschiedenen Einzelteilen? Wenn ja, dann doppelte Einträge, die nicht eindeutig ist, was immer schlecht Usability Design ist. Wenn nicht, dann haben Sie sollten keine doppelten Einträge.

Das einzige Szenario, das ich denken kann, wo dies Sinn machen könnte, ist, wenn Sie eine große Liste haben, bestehend aus mehreren Gruppen verwandter Elemente, in denen ein oder mehr Objekte logisch in mehr als eine Gruppe passen, so dass Sie es in beiden Abschnitten angezeigt werden sollen.

Ich schätze, dass Ihr Design nicht die Tatsache berücksichtigen haben, dass es mehrere identische Einträge vorhanden sein können, und dass diese Auslassung werden andere Usability Auswirkungen haben, als dieses Problem mehr von Bedeutung sind. Natürlich verstehe ich, dass Sie etwas tun, kann ich nicht gedacht haben, wo es Sinn macht total zu tun, was Sie tun, in dem Fall, dass Sie von mir frei fühlen können, zu ignorieren.

Beantwortet am 30/03/2009 um 07:54
quelle vom benutzer

stimmen
1

Es gibt Fälle, in denen mit doppelten Elementen in der Liste nicht nur gültig ist, aber wünschenswert. Betrachten Sie die Openfile Combo-Box, die Sie in Visual Studio zu sehen, wenn Sie die Datei öffnet Taste drücken. Dies zeigt ein Kombinationsfeld mit Elementen wie ‚Arbeitsplatz‘, ‚Desktop‘, ‚Eigene Dateien‘, usw. Für Ordnernamen, nur der Kurzname ist in der Liste. Der vollständige Pfad wird nicht angezeigt. Und so ist es durchaus möglich, dass ein Ordner mit dem gleichen (kurz) Namen als einer seiner Nachkommen hat.

So stellen Sie sich die folgende Ordnerstruktur:

C:\
C:\A
C:\A\B
C:\A\B\A

Eine perfekt gültige Struktur. In meiner Implementierung stelle ich die Datasource-Eigenschaft auf ein Binding von Objekten. Die Valuemember des Objekts sind die vollständigen Dateinamen und die Display ist die kurzen Dateinamen. Das Kombinationsfeld soll angezeigt werden:

C:\
    A
        B
            A

Perfekt gutes UI-Design. Die Vertiefung schlägt die Verschachtelung der Ordner.

Aber wenn ich die SelectedValue des Kombinationsfelds auf „C: \ A \ B \ A“ das falsche Einzelteil wird ausgewählt. Das Element, das ausgewählt werden soll, ist das letzte (vierte Element) in der Liste, sondern das zweite Element (Index 1) ausgewählt ist. Und SelectedIndex Einstellung = 3 verhält sich nicht wie beabsichtigt. Auch hier ist das zweite Element ausgewählt, nicht der letzte.

Was geschieht, scheint hier zu sein, ist, dass, wenn SelectedValue oder SelectedIndex Einstellung wird der Wert der Eigenschaft Display umgewandelt wird unter Verwendung, und die Steuerung wird die Suche von Anfang an für ein Spiel zu beenden. Man sollte die Suche im Valuemember Eigenschaft. Beispielcode ist unten. Geschätzt wenn jemand bestätigen kann dies ein Fehler ist, oder etwas, was ich falsch gemacht habe.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ComboBoxTest
{
   public partial class Form1 : Form
   {
      public Form1()
      {
         InitializeComponent();
      }

      private void Form1_Load(object sender, EventArgs e)
      {
         if (DesignMode)
            return;

         BindingList<CBItem> items = new BindingList<CBItem>();
         items.Add(new CBItem("A", @"C:\A"));
         items.Add(new CBItem("B", @"C:\A\B"));
         items.Add(new CBItem("A", @"C:\A\B\A"));

         comboBox.DisplayMember = "DisplayValue";
         comboBox.ValueMember = "RealValue";
         comboBox.DataSource = items;

         comboBox.SelectedValue = @"C:\A\B\A";
      }
   }

   class CBItem
   {
      public CBItem(string displayValue, string realValue)
      {
         _displayValue = displayValue;
         _realValue = realValue;
      }

      private readonly string _displayValue, _realValue;

      public string DisplayValue { get { return _displayValue; } }
      public string RealValue { get { return _realValue; } }
   }
}
Beantwortet am 28/05/2009 um 21:38
quelle vom benutzer

stimmen
0

Ein ähnliches Problem tritt ohne identische Elemente mit, wenn Sie freien Text eingeben, der nicht genau übereinstimmt, aber die ersten Zeichen. Wenn der Benutzer nicht öffnet die Drop-down keine erneute Synchronisierung passieren und der ausgewählte Index -1 ist wie erwartet. (Nicht einer der Elemente ausgewählt ist, was der Benutzer zu tun beabsichtigt) Nun der Benutzer schließt den Dialog und öffnen Sie sie erneut. Sie als Programmierer, stellen Sie die Combobox mit dem Text der Benutzer eingegeben und der Text wird automatisch beendet das Element teilweise Übereinstimmung, ohne das Ereignis zu feuern. Wenn der Benutzer den Dialog geschlossen wird der Text ohne vorherige Ankündigung geändert werden. Dieses Problem tritt nicht auf, wenn der Text nicht ein beliebiges Element entspricht.

Beantwortet am 28/06/2009 um 11:15
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more