2012-06-22 4 views
2

Я хочу, чтобы бесплатный тип в combobox. Когда я перестаю печатать, у меня есть задание с задержкой, которое заполняет элементы со списком с некоторыми зависимыми от ввода результатами. Проблема в том, что мой ввод переопределяется первым элементом в списке. Есть ли способ сохранить свой вклад?Combobox = текстовое поле + список

Мой пример кода происходит так:

public void PopulateCombo(JObject result) 
    { 
     Debug.WriteLine("Thread id: " + Thread.CurrentThread.ManagedThreadId); 

     cbSearch.Items.Clear(); 
     if (result.Value<bool>("success") == true) 
     { 
      JArray arr = result.Value<JArray>("data"); 
      for (int i = 0; i < arr.Count; i++) 
      { 
       JToken item = arr[i]; 
       cbSearch.Items.Add(new ComboBoxItem(item.Value<string>("name"), item.Value<string>("_id"))); 
      } 
      cbSearch.DroppedDown = true; 
     } 
    } 

отредактированные на 23,06

Я привожу пример того, что я на самом деле пытается сделать.

  1. выпадающий не пуста (нет товаров)
  2. Пользователь начинает вводить, например, "JA". Combobox отправляет запрос на мой сервер. Не должно быть проблем, так как вызов асинхронный с 1 секундой задержки после последнего ввода пользователя.
  3. Мои бэкэнд возвращает некоторые результаты (Антон Джеймисон, Джеймс Аарон, Джеймс Хетфилд и т. Д., Ограниченный до 50)
  4. Я хочу заполнить выпадающий список результатами, чтобы открыть его, но в виде текста со списком я хочу держите «ja», чтобы пользователь мог уточнить свой поиск дальше.
  5. Пользователь расширяет поиск "ja h". Бэкэнд отвечает Джеймсом Хетфилдом. Результат теперь всего лишь один элемент, и теперь я могу установить текст со списком или сохранить поведение сверху. Не уверен, что еще лучше.

Все это реализовано, но на этапе 4, когда я заполняю поле со списком, используя приведенную выше функцию, текст комбо изменяется с «ja» на первое совпадение списка. (Антон Джеймисон в примере). Я почти уверен, что был простой вариант для реализации этого поведения, но я не уверен, было ли это на C#.

На комментарии:

  1. Это была хорошая попытка, но неудачно. Когда я заполняю элементы combobox, моя строка поиска изменяется на первое совпадение списка.
  2. Я думаю, что я не пытаюсь реализовать функцию автозаполнения.
  3. Хорошо поймите о DroppedDown. Я перемещаю его в отредактированной версии.
+0

Не можете ли вы захватить «combobox.text» перед тем, как заполнить список, а затем восстановить его после популяции? – Charleh

+1

Вы пытаетесь реализовать автозаполнение? Если это так, он уже построен в: http://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.autocompletemode.aspx – Tergiver

+0

Невозможно воспроизвести проблему. Возможно, вы захотите переместить строку 'DroppedDown = true;' после цикла for .... – LarsTech

ответ

1

У меня нет проблемы, о которой вы говорили. Текст в поле редактирования остается неизменным все время. Я использую VS2008, хотя со стандартным ComboBox, переименованным в cbSearch, и его захваченным событием (а также событием шоу формы). Отдых работает красиво.

Казалось, что это хорошая задача, поэтому я сделал это. Я также восстанавливаю выделение, хотя вы можете видеть мерцание.

Наиболее сложной была синхронизация - поэтому я нашел легкое не уродливое решение.

Тем не менее, я ничего не делаю от вас. Возможно, вы снова начинаете с пустой ComobBox, возможно, вы изменили некоторые параметры по умолчанию.

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

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

     private void cbSearch_TextUpdate(object sender, EventArgs e) 
     { 
      lastUpdate = DateTime.Now; 
      allowUpdate = true; 
     } 
     DateTime lastUpdate = DateTime.Now; 

     volatile bool allowUpdate = false; 
     private void BoxUpdate() 
     { 
      while (true) 
      { 
       Thread.Sleep(250); 
       if (allowUpdate) 
       { 
        var diff = DateTime.Now - lastUpdate; 
        if (diff.TotalMilliseconds > 1500) 
        { 
         allowUpdate = false; 
         this.InvokeEx(x => 
         { 
          if (x.cbSearch.Text.Length > 0) 
          { 
           x.PopulateCombo(cbSearch.Text); 
          } 
         }); 
        } 
       } 
      } 
     } 

     public void PopulateCombo(string text) 
     { 
      int sStart = cbSearch.SelectionStart; 
      int sLen = cbSearch.SelectionLength; 

      List<string> cbItems = new List<string>(); 
      for (int i = 0; i < 3; ++i) 
       for (int j = 0; j < 3; ++j) 
        cbItems.Add(i + text + j); 

      cbSearch.Items.Clear(); 

      { 
       for (int i = 0; i < cbItems.Count; i++) 
       { 
        cbSearch.Items.Add(cbItems[i]); 
       } 
       cbSearch.DroppedDown = true; 
      } 

      cbSearch.SelectionStart = sStart; 
      cbSearch.SelectionLength = sLen; 
     } 

     private void Form1_Shown(object sender, EventArgs e) 
     { 
      ThreadPool.QueueUserWorkItem(x => 
      { 
       BoxUpdate(); 
      }); 
     } 
    } 

    public static class ISynchronizeInvokeExtensions 
    { 
     public static void InvokeEx<T>(this T @this, Action<T> action) 
      where T : System.ComponentModel.ISynchronizeInvoke 
     { 
      if (@this.InvokeRequired) 
      { 
       @this.Invoke(action, new object[] { @this }); 
      } 
      else 
      { 
       action(@this); 
      } 
     } 
    } 
} 
0

Управляется с тем же заданием с подсказкой комментария 1 + некоторые настройки.Вот мой последний код, который делает работу:

private void cbSearch_TextUpdate(object sender, EventArgs e) 
    { 
     timer1.Stop(); 
     timer1.Dispose(); 
     timer1 = null; 

     timer1 = new System.Windows.Forms.Timer(); 
     timer1.Tick += new EventHandler(timer1_Tick); 
     timer1.Interval = 1000; 
     timer1.Start(); 
    } 

    delegate void MethodDelegate(JObject result); 

    void timer1_Tick(object sender, EventArgs e) 
    { 
     timer1.Stop(); 
     Debug.WriteLine(this.cbSearch.Text); 

     Debug.WriteLine("Thread id: " + Thread.CurrentThread.ManagedThreadId); 
     Dictionary<string, object> parameters = new Dictionary<string, object>(); 
     parameters["query"] = this.cbSearch.Text ?? ""; 
     this.session.rpc["advanced_search"].execAsync(parameters, results => 
     { 
      this.BeginInvoke(new MethodDelegate(PopulateCombo), new object[] {results.GetResult()}); 
     }); 
    } 

    public void PopulateCombo(JObject result) 
    { 
     Debug.WriteLine("Thread id: " + Thread.CurrentThread.ManagedThreadId); 

     this.selectedPatientId = ""; 
     string text = cbSearch.Text; 
     cbSearch.DroppedDown = false; 

     cbSearch.Items.Clear(); 
     if (result.Value<bool>("success") == true) 
     { 
      JArray arr = result.Value<JArray>("data"); 
      for (int i = 0; i < arr.Count; i++) 
      { 
       JToken item = arr[i]; 
       cbSearch.Items.Add(new ComboBoxItem(item.Value<string>("name"), item.Value<string>("_id"))); 
      } 

      try 
      { 
       this.cbSearch.TextUpdate -= new System.EventHandler(this.cbSearch_TextUpdate); 
       cbSearch.DroppedDown = true; 
       cbSearch.Text = text; 
       cbSearch.Select(cbSearch.Text.Length, 0); 

      } 
      finally { 
       this.cbSearch.TextUpdate += new System.EventHandler(this.cbSearch_TextUpdate); 
      } 
     } 
    } 
Смежные вопросы