【问题标题】:BackgroundWorker for implementing "Search as you type" ComboboxBackgroundWorker 用于实现“键入时搜索”组合框
【发布时间】:2012-08-14 03:55:25
【问题描述】:

我为我的组合框创建了一个代码,它可以在存储过程的帮助下在 Sql Server 上的一个非常大的表中搜索地址(我正在使用实体框架)。我的存储过程返回 10 次点击,我的代码用搜索结果填充组合框。为此,我正在使用 BackgroundWorker。

但是我现在遇到了大问题: - 虽然组合框充满了我的搜索结果,但它总是选择第一个项目。即使我只输入一个字母,整个文本也会被选中;

  • 之后搜索地址不再起作用。它只在这 10 个结果中搜索,我不知道如何解决这个问题。这是我的整个代码,这给我带来了问题:

    public String searchedItem = "";    
    public delegate void DelegateUpdateComboboxSelection(ComboBox myCombo,string value,int count);
    
    BackgroundWorker m_bgworker = new BackgroundWorker();        
    static AutoResetEvent resetWorker = new AutoResetEvent(false);
    
    m_bgworker.WorkerSupportsCancellation = true;
    m_bgworker.DoWork += new DoWorkEventHandler(FillComboboxBindingList);
    m_bgworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_bgworker_RunWorkerCompleted);
    
    BindingList<spIskalnikNaslovi_Result1> m_addresses = new BindingList<SP_Result1>(); 
    
    
    void m_bgworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        int count = (int)((object[])e.Result)[0];
        string value = (string)((object[])e.Result)[1];
        ComboBox myCombo = (ComboBox)((object[])e.Result)[2];
        DelegateUpdateComboboxSelection ndelegate = new DelegateUpdateComboboxSelection(UpdateComboSelection);
        if (this.InvokeRequired)
        {
            Invoke(ndelegate, new object[] {myCombo, value, count});
            return; 
        }
        else
        {
            UpdateComboSelection(myCombo, value, count);
            return; 
        }               
    }
    
    private void UpdateComboSelection(ComboBox myCombo, String value, int count)
    {
        myCombo = comboBox9;
        myCombo.DataSource = m_addresses;
        searchedItem = myCombo.Text;  
        if (count > 0)
        {
            myCombo.SelectionStart = value.Length;
            myCombo.SelectionLength = searchedItem.Length - value.Length;
            myCombo.DroppedDown = true;
        }
        else
        {
            myCombo.DroppedDown = false;
            myCombo.SelectionStart = value.Length;
        }
    } 
    
    public void FillComboboxBindingList(object sender, DoWorkEventArgs e)
    {
        if (m_bgworker.CancellationPending)
        {
            resetWorker.Set();
            e.Cancel = true;
            return;
        }
        else
        {
            string value = (String)((Object[])e.Argument)[0];
            List<SP_Result1> result;
            result = _vsebina.SP_searcher(value).ToList<SP_Result1>();
            m_addresses = new BindingList<SP_Result1>();
    
            foreach (SP_Result1 rez in result)
            {
                if (m_addresses.Contains(rez))
                {
                    continue;
                }
                else
                {
                    m_addresses.Add(rez);
                }
            }
            foreach (SP_Result1 r in m_addresses.ToArray())
            {
                if (!result.Contains(r))
                {
                    m_addresses.Remove(r);
                }
            }
            e.Result = new object[] { rezultat.Count, vrednost, null };
            return;
        }
    }
    
    private void comboBox9_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Back)
        {
            int searchStart = comboBox9.SelectionStart;
            if (searchStart > 0)
            {
                searchStart--;
                if (searchStart == 0)
                {
                    comboBox9.Text = "";
                }
                else
                {
                    comboBox9.Text = comboBox9.Text.Substring(0, searchStart + 1);
                }
            }
            else 
            {
                searchStart = 0;
            }
            e.Handled = true;
        }
    }
    
    private void comboBox9_Enter(object sender, EventArgs e)
    {
        comboBox9.SelectionStart = 0;
        comboBox9.SelectionLength = 0;
    }
    
    private void comboBox9_Click(object sender, EventArgs e)
    {
        comboBox9.Text = "";
    }
    
    private void comboBox9_KeyPress(object sender, KeyPressEventArgs e)
    {
        Search();
    }
    
    public void Search()
    {
        if (comboBox9.Text.Length < 4)
        {
            return;
        }
        else
        {
            if (m_bgworker.IsBusy)
            {
               m_bgworker.CancelAsync();
    
               m_bgworker = new BackgroundWorker();
               m_bgworker.WorkerSupportsCancellation = true;
               m_bgworker.DoWork += new DoWorkEventHandler(FillComboboxBindingList);
               m_bgworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_bgworker_RunWorkerCompleted);
            }
            m_bgworker.RunWorkerAsync(new object[] { comboBox9.Text, comboBox9 });
        }  
    }
    

也许有人可以启发我,我做错了什么。这是我第一次使用 BackgroundWorker。我不知道,如何 以任何其他方式使用组合框实现“键入时搜索”,因为我的地址数据表非常大(百万条记录)。

在此先感谢您提供任何帮助或代码示例。

弗拉基米尔

编辑 1: 好的,这是我使用 BackGroundWorker 之前的代码。它有效,但搜索速度非常慢(最多可能需要 10 秒):

    private void comboBox9_TextChanged(object sender, EventArgs e)
    {
        if (comboBox9.Text.Length < 4)
        {
            return;
        }
        else
        {
            FillCombobox(comboBox9.Text, comboBox9);
        }

    }

    public void FillCombobox(string value, ComboBox myCombo)
    {
        List<spIskalnikNaslovi_Result1> result;
        result = _vsebina.spIskalnikNaslovi1(value).ToList(); 
        if (result.Count() > 0)
        {
            myCombo.DataSource = result;
            myCombo.ValueMember = "HS_MID";
            myCombo.DisplayMember = "NASLOV1";
            var searchedItem = myCombo.Items[0].ToString();
            myCombo.SelectionStart = value.Length;
            myCombo.SelectionLength = searchedItem.Length - value.Length;
            myCombo.DroppedDown = true;
        }
        else
        {
            myCombo.DroppedDown = false;
            myCombo.SelectionStart = value.Length;
        }
        return;
    }

有没有办法在没有后台工作人员的情况下加快速度?

【问题讨论】:

  • 你的组合框不是已经有一个自动完成模式可以使用,而不是使用后台工作人员吗?
  • 当然它有一个自动完成模式,但在我使用 BackgroundWorker 的情况下它不能很好地工作。我需要 backgroundWorker,因为在正常情况下,搜索每个键入的字符会花费您太多时间(在我的情况下大约 10 秒)。

标签: c# search frameworks combobox entity


【解决方案1】:

这是我没有 BackGroundWorker 的最终解决方案。它适用于我的大表,并已升级为使用 SQL Server 上的存储过程(如果您使用实体框架)。我使用 Timer 来确保用户可以找到他正在搜索的值。

在这里你可以看到我在这个网站上找到的原始解决方案(感谢 Max Lambertinialgreat 的想法和工作理念):

C# winforms combobox dynamic autocomplete

我的解决方案:

    private bool _canUpdate = true;
    private bool _needUpdate = false;
    List<spIskalnikNaslovi_Result1> dataFound;

    private void comboBox12_TextChanged(object sender, EventArgs e)
    {
        if (_needUpdate)
        {
            if (_canUpdate)
            {
                _canUpdate = false;
                refreshData();
            }
            else
            {
                restartTimer();
            }
        }
    }

    private void comboBox12_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Back)
        {
            int searchStart = comboBox12.SelectionStart;
            if (searchStart > 0)
            {
                searchStart--;
                if (searchStart == 0)
                {
                    comboBox12.Text = "";
                }
                else
                {
                    comboBox12.Text = comboBox12.Text.Substring(0, searchStart + 1);
                }
            }
            else 
            {
                searchStart = 0;
            }
            e.Handled = true;
        }
    }

    private void comboBox12_TextUpdate(object sender, EventArgs e)
    {
        _needUpdate = true;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        _canUpdate = true;
        timer1.Stop();
        refreshData();
    }

    private void refreshData()
    {
        if (comboBox12.Text.Length > 1)
        {
            FillCombobox(comboBox12.Text, comboBox12);
        }
    }

    private void restartTimer()
    {
        timer1.Stop();
        _canUpdate = false;
        timer1.Start();
    }


    private void FillCombobox(string value, ComboBox myCombo)
    {
        dataFound = _vsebina.spIskalnikNaslovi1(value).ToList();
        if (dataFound.Count() > 0)
        {
            myCombo.DataSource = dataFound;
            myCombo.ValueMember = "HS_MID";
            myCombo.DisplayMember = "NASLOV1";
            var searchedItem = myCombo.Items[0].ToString();
            myCombo.SelectionStart = value.Length;
            myCombo.SelectionLength = searchedItem.Length - value.Length;
            myCombo.DroppedDown = true;
            return;
        }
        else
        {
            myCombo.DroppedDown = false;
            myCombo.SelectionStart = value.Length;
            return;
        }            
    }

【讨论】:

    【解决方案2】:

    对于“Search as you Type”,实际上是“Filter as you Type”而不是搜索,需要实现OnKeyDown或KeyPressed事件。

    您要做的是获取搜索字符串,即事件发生时的当前文本,然后使用该字符串过滤主列表。通常人们会使用“开始于”进行过滤,但您也可以简单地使用“包含”。然后,您使用过滤器的结果实时更新框的内容。这是通过更改和刷新数据源来完成的。

    【讨论】:

      【解决方案3】:

      您应该将您的项目放在一个列表中,使用该列表来填充您的组合框。

      然后将 AutoCompleteMode 属性值设置为 Suggest 或 Append 或 SuggestAppend 并将 AutoCompleteSoucre 属性值设置为 ListItems。

      【讨论】:

      • 我的 ComboBox 有 SuggestAppend 并且作为 AutoCompleteSource 它有 ListItems。自动完成与我以前的代码一起工作。它只是慢得令人痛苦。
      【解决方案4】:

      制作一个按钮,您将调用 searchbutton 并在此按钮的 click_event 中调用运行 backgroundworker 的 search() 方法 填充组合框 清除组合框的 key_press 事件,它将起作用 错误是您的 key_press 事件调用发生在您的搜索方法中的每个按键 所以找回来

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-26
        • 2013-08-30
        • 1970-01-01
        • 2023-04-05
        • 2014-08-15
        • 2017-10-04
        • 2022-12-08
        • 2013-03-30
        相关资源
        最近更新 更多