Поле автозаполнения - противоречивые значения от населения - PullRequest
3 голосов
/ 27 декабря 2011

У меня есть приложение WPF с окном автозаполнения через инструментарий (VS 2008). У меня есть потенциальная популяция около 2000 записей, и я пытался улучшить производительность с помощью комбинации процедуры заполнения событий. Я получаю противоречивые результаты. Фильтр вроде бы в порядке, но я могу запустить приложение один раз, и результат X будет там, но результат Y не будет. Повторный запуск может привести к тому, что Y будет там, а не X, в последующие моменты времени будут присутствовать X и Y и т. Д., И т. Д. Я впервые использую поле автозаполнения, поэтому я уверен, что в моем коде должно быть что-то, что я забываю Если я проверяю свой набор результатов непосредственно перед привязкой Itemsource, желаемые результаты есть, но они не становятся видимыми пользователю - выпадающий список автозаполнения не отображается. Может быть, мне нужно переопределить событие ???

XAML

<input:AutoCompleteBox                         
Name="autGlobal"
FilterMode="Contains"
Style="{DynamicResource MiniSearchAutoBoxWPF}"
IsTextCompletionEnabled="false" 
Margin="5, 0, 5, 0" 
HorizontalAlignment="Center"
KeyUp="autGlobal_KeyUp"
Text="Search Term" 
GotFocus="autGlobal_GotFocus"
ValueMemberPath="Item" 
Populating="AutoCompleteBox_Populating"
>

Методы

 private void AutoCompleteBox_Populating(object sender, PopulatingEventArgs e)
            {
            e.Cancel = true;
            var b = new BackgroundWorker();
            currSearch = autGlobal.Text;
            b.DoWork += b_DoWork;
            b.RunWorkerCompleted += b_RunWorkerCompleted;
            b.RunWorkerAsync(autGlobal.Text);
        }

private void b_DoWork(object sender, DoWorkEventArgs e)
        {
            Results.Clear();
            int counter = 0;
            string search = e.Argument.ToString();
            search = search.ToUpper();
            foreach (GlobalSearchList person in myGlobalList)
            {
                if (person.Item.ToUpper().Contains(search))
                {
                    Results.Add(person);
                    counter++;

                    if (counter >= MAX_NUM_OF_RESULTS)
                    {                        
                        break;
                    }
                }
            }
        }

private void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            if (this.Dispatcher.Thread == System.Threading.Thread.CurrentThread)
            {
                //Set the source
                if (currSearch == autGlobal.Text)
                {
                    autGlobal.ItemsSource = Results;
                    autGlobal.PopulateComplete();
                }
            }
            else
            {
                this.Dispatcher.Invoke(new Action(() =>
                {
                    //Set the source
                    if (currSearch == autGlobal.Text)
                    {
                        autGlobal.ItemsSource = Results;
                        autGlobal.PopulateComplete();
                    }

                }));
            }            
        }

Ответы [ 2 ]

3 голосов
/ 02 января 2012

Я не уверен, зачем вам в первую очередь повышение производительности, вы пытаетесь вычислить элементы, которые должны быть в поле Автозаполнение в другом потоке, а затем назначить их свойству ItemsSource элемента управления , Нечто похожее - то, что должен делать AutoCompleteBox.

Я попытался привязать элемент управления к списку с 10000 строками, и он отлично работает, поэтому вашей проблемой может быть размер объектов, которые вы помещаете в коллекцию. Одним из решений может быть использование только строкового представления, а затем, когда вам нужен выбранный объект, вы можете найти его на основе его представления, предполагая, что оно уникально (если нет, вы можете указать какой-то идентификатор).

Одной из основных проблем этого подхода является синхронизация потоков, теперь я объясню, почему вы получаете поведение extrange, когда даже при хорошем фильтре элементы в результатах не верны.

Фильтр вроде бы в порядке, но я могу запустить приложение один раз, и результат X будет быть там, но результат Y не будет. Повторный запуск может привести к там, а не X, последующие времена будут и X, и Y, и т. д., и т.д.

Предположим, что вы напишите «ab» в поле автозаполнения, это запустит новый BackGroundWorker, где будет выполняться этот поиск. Все должно быть хорошо, если вы будете ждать достаточно долго. Но если вы измените поисковый запрос до того, как первый работник закончил, теперь все результаты будут смешанными. Возьмем, к примеру, следующие строки кода:

// the user searchs for "ab"
[Thread 1] Results.Clear();
[Thread 1] Results.Add(Item[1]);
[Thread 1] Results.Add(Item[2]);
...
// the user changes the search term (to "abc" for example)
[Thread 2] Results.Clear();
[Thread 2] Results.Add(Item[3]);
// but what would happen if the first BackGroundWorker hasn't finished yet,
// this means that the first thread is still running
[Thread 1] Results.Add(Item[5]); // this items doesn't match the second search
[Thread 1] Results.Add(Item[6]); // criteria, but are added to the collection
[Thread 2] Results.Add(Item[7]);
// then you'll have two treads adding items to the Result collection
[Thread 1] Results.Add(Item[2]);
...
[Dispatcher Thread] autGlobal.ItemsSource = Results;
[Dispatcher Thread] autGlobal.PopulateComplete();

Надеюсь, это поможет.

0 голосов
/ 30 декабря 2011

Может быть, вы могли бы проверить это. Вся работа сделана для вас.

http://gallery.expression.microsoft.com/WPFAutoCompleteBox/

...