Feedback

C# - Searchable ComboBox

Veröffentlicht von am 3/30/2011
(2 Bewertungen)
Eine ComboBox, in der nach den enthaltenen Einträgen gesucht werden kann.
Es können keine neuen Einträge eingefügt werden und nur Begriffe eingegeben werden, die auch in der Liste enthalten sind.
using System;
using System.Windows.Forms;

namespace MyUserControls
{
    /// <summary>
    /// ComboBox, die es ermöglicht, die darin enthaltenen
    /// Einträge zu suchen, jedoch keine neuen anzulegen.
    /// </summary>
    public class SearchableComboBox : ComboBox
    {
        /// <summary>
        /// Initialisiert eine durchsuchbare ComboBox.
        /// </summary>
        public SearchableComboBox()
        {
            // Autovervollständigung einschalten
            this.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            this.AutoCompleteSource = AutoCompleteSource.ListItems;

            // Einfügen von Text mittels Kontextmenüs verhindern
            this.ContextMenu = new ContextMenu();

            // Einzelne Tastendrücke abfangen
            this.KeyPress += new KeyPressEventHandler(SearchableComboBox_KeyPress);
        }

        /// <summary>
        /// Wird aufgerufen, wenn eine Taste gedrückt wird.
        /// Überprüft, ob es sich um eine gültige Taste handelt.
        /// </summary>
        private void SearchableComboBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Bei der Löschtaste die Methode verlassen
            if (e.KeyChar == '\b')
                return;

            string searchString = String.Concat(this.SelectedText != "" ? this.Text.Replace(this.SelectedText, "") : this.Text, 
                e.KeyChar.ToString());
            bool success = false;

            // Alle Einträge überprüfen, ob ein passender gefunden werden kann
            foreach (object item in this.Items)
            {
                if (item.ToString().StartsWith(searchString))
                {
                    success = true;
                    break;
                }
            }

            // Wenn es nicht erfolgreich war, den Tastendruck verhindern
            if (!success)
                e.Handled = true;
        }

        /// <summary>
        /// Verhindert das Einfügen von Text mithilfe von Strg + V.
        /// </summary>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == (Keys.Control | Keys.V))
                return true;
            else
                return base.ProcessCmdKey(ref msg, keyData);
        }
    }
}
Abgelegt unter combobox, cb, searchable, suchen, suche.

7 Kommentare zum Snippet

Marcus schrieb am 3/31/2011:
Hi Curry,

ich habe das Snippet mal unter die Lupe genommen und konnte kleine Fehler finden.

1. Alle Buchstaben bist auf den ersten müssen doppelt eingegeben werden, damit sie angezeigt werden.
Die Prüfung hattest du bereits schon, doch kommt es bei dieser zu falschen Werten.

Ersetze
string searchString = String.Concat(this.SelectedText != "" ? this.Text.Replace(this.SelectedText, "") : this.Text, 
e.KeyChar.ToString());


mit
string searchString = string.Concat(this.SelectedText != string.Empty ? 
this.Text.Replace(this.SelectedText, string.Empty) : this.Text, e.KeyChar.ToString());


2. Wenn in die Combobox beispielsweise eigene Klassen aufgenommen werden, schlägt der Vergleich mit item.ToString() immer fehl, da diese nicht den eigentlichen Wert enthält.

Sobald also nun in this.DisplayMember ein Wert steht, sollte dieser auf vom Objekt abgerufen werden.

Somit sieht mein Schleifeninhalt wie folgt aus:
bool readFromProperty = this.DisplayMember != string.Empty;
string fieldText;

// Alle Einträge überprüfen, ob ein passender gefunden werden kann
foreach (object item in this.Items)
{
fieldText = item.ToString();

if (readFromProperty)
{
System.Reflection.PropertyInfo tmpInfo = item.GetType().GetProperty(this.DisplayMember);

if (tmpInfo != null)
{
fieldText = tmpInfo.GetValue(item, null).ToString();
}
}

if (fieldText.StartsWith(searchString))
{
success = true;
break;
}
}
Curry schrieb am 3/31/2011:
Hi,

danke dass du dir das Snippet angesehen hast.

Zu 1.: Du hast doch nicht anderes gemacht, als "" durch String.Empty auszutauschen? Und ich muss keinen Buchstaben doppelt eingeben.

2.: Ok, das stimmt sehr wohl :-)
Christopher Kk schrieb am 3/31/2011:
Mir ist gerade nicht ganz klar warum du so ein Aufwand betriebst? Für Comboboxes gibts doch AutoCompletion Sources und auch AutoCompletion-Modies mit denen man genau das von dir simulierte bereites umsetzen kann. Hat das einen bestimmten Grund?
Marcus schrieb am 3/31/2011:
@Curry
ja, ich habe nur "" zu string.Empty ersetzt. Dadurch hat es bei mir auch funktioniert.
Es ist generell besser string.Empty statt "" zu verwenden.

@Christopher
Genau das habe ich mir zuerst auch gedacht. Aber als ich gesehen hatte, dass er die
            // Autovervollständigung einschalten
this.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
this.AutoCompleteSource = AutoCompleteSource.ListItems;
setzt, musste ich mir den code genauer ansehen.

Ziel des Codes ist es, dass der Benutzer in der Combobox nur Texte eingeben kann, die in der Collection vorhanden sind.
Curry schrieb am 3/31/2011:
Ja, gibt es.
Ich benutze in diesem Fall ja auch AutoCompletion. Allerdings soll man keine Werte hineinschreiben können, die nicht existieren. Und dafür gibt es meines Wissens keine Bordmittel-Lösung.
Hab das Control in ein DataGridViewColumn integriert. Falls jemand daran intressiert ist, kann ich das ganze ja mal posten.
Christopher Kk schrieb am 3/31/2011:
Ahh alles klar verstehe es jetzt.
Aber wenn ich die Bordmittel nutze und was in der Box eingebe was es nicht gibt, dann wird mir doch auch nichts vorgeschlagen und dann sollte doch bei jedem halbwegs entwickelten Menschen im Kopf klar sein, dass es keine Elemente gibt mit dem Suchbegriff oder? :) Ansonsten sauberes Snippet, kriegst volle Punkte von mir.
Curry schrieb am 3/31/2011:
Danke :-)
Ja, aber bei mir in der Firma kann man sich bei den Usern nicht so ganz sicher sein, ob die über einen gesunden Menschenverstand verfügen ;P Man muss immer mit dem dümmsten User rechnen :-)
 

Logge dich ein, um hier zu kommentieren!