Combobox =文本框+列表

时间:2012-06-22 20:43:57

标签: c#

我想免费输入组合框。当我停止输入时,我有一个延迟的任务,用一些输入相关的结果填充组合框项目。问题是我的输入被列表中的第一项覆盖。有没有办法保持我的意见?

我的示例代码如下:

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. Combobox为空(无项目)
  2. 用户开始输入例如“ja”。 Combobox向我的后端发送查询。不应该是一个问题,因为在用户上次输入后,调用是异步的,延迟1秒。
  3. 我的后端返回一些结果(Anton Jamison,James Aaron,James Hetfield等,限于50)
  4. 我想用结果填充下拉列表,打开它,但作为一个组合框文本,我想保留“ja”,这样用户就可以进一步澄清他的搜索。
  5. 用户扩展了他的搜索“ja h”。后端回应James Hetfield。结果现在只有一个项目,我现在可以设置组合框文本或保持上面的行为。不确定哪个更好。
  6. 所有这些都已实现,但在步骤4中,当我使用上述函数填充组合框时,组合的文本从“ja”更改为列表的第一个匹配项。 (示例中的安东贾米森)。我几乎可以肯定,实现这种行为有一个简单的选择,但我不确定它是否在C#中。

    评论:

    1. 这是一次不错的尝试但不成功。填充组合框项目后,我的搜索字符串将更改为列表的第一个匹配项。
    2. 我想我不会尝试实现自动完成功能。
    3. 关于DroppedDown的好消息。我在编辑后的版本中移动它。

2 个答案:

答案 0 :(得分:1)

我没有你谈到的问题。编辑框中的文本始终保持不变。 我正在使用VS2008,但标准的ComboBox重命名为cbSearch并捕获其事件(以及表单的show事件)。 休息很好。

看起来像一个很好的任务,所以我做到了。 我也恢复了选择,虽然你可以看到一些闪烁。

最困难的是同步 - 所以我找到了一个简单而不太难看的解决方案。

尽管如此,我没有做任何与你不同的事情......也许你再次开始使用空白的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);
            }
        }
    }
}

答案 1 :(得分: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);
            }
        }
    }