2

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

我的示例代码是这样的:

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”。组合框向我的后端发送查询。应该不是问题,因为调用是异步的,在用户最后一次输入后有 1 秒的延迟。
  3. 我的后端返回一些结果(Anton Jamison、James Aaron、James Hetfield 等,限制为 50)
  4. 我想用结果填充下拉列表,打开它,但作为组合框文本,我想保留“ja”,以便用户可以进一步澄清他的搜索。
  5. 用户扩展了他的搜索“ja h”。后端以 James Hetfield 响应。现在的结果只有一项,我现在可以设置组合框文本或保留上面的行为。不确定哪个会更好。

所有这些都已实现,但在第 4 步,当我使用上面的函数填充组合框时,组合的文本从“ja”更改为列表的第一个匹配项。(示例中的安东·贾米森)。我几乎可以肯定有一个简单的选项可以实现这种行为,但我不确定它是否在 C# 中。

关于评论:

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

2 回答 2

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);
            }
        }
    }
}
于 2012-06-27T16:51:50.580 回答
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);
            }
        }
    }
于 2012-07-05T11:44:24.057 回答