BackgroundWorker用于实现“在键入时搜索”Combobox

时间:2012-08-17 17:17:25

标签: c# search frameworks combobox entity

我已经为我的组合框创建了一个代码,它可以借助存储过程(我正在使用Entity框架)在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。我不知道,怎么样 以任何其他方式使用combobox实现“在键入时搜索”,因为我的地址数据表非常大(百万条记录)。

提前感谢任何类型的帮助或代码示例。

弗拉基米尔

编辑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;
    }

有没有办法在没有背景工作者的情况下加快速度?

4 个答案:

答案 0 :(得分:0)

创建一个按钮,您将调用searchbutton 并在此按钮的click_event中调用运行backgroundworker的search()方法 填充组合框 清除你的组合框的key_press事件,它会工作 错误是你key_press事件调用你的搜索方法发生的每个键击 检索它

答案 1 :(得分:0)

您应该将项目放入列表中,使用该列表填充组合框。

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

答案 2 :(得分:0)

对于“当您键入时搜索”,实际上“搜索时过滤”而不是搜索,您需要实现OnKeyDown或KeyPressed事件。

您要做的是获取搜索字符串,即事件发生时的当前文本,然后使用该字符串过滤主列表。通常会使用“Starts With”进行过滤,但您也可以使用“Contains”。然后你实时用过滤器的结果更新盒子的内容。这是通过更改和刷新数据源来实现的。

答案 3 :(得分:0)

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

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

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;
        }            
    }