WPF, работа с ListCollectionView в фоновом потоке — как исправить ошибку?

Есть большая таблица в DataGrid. Следующая функция выполняется в фоновом потоке. Первый раз срабатывает. Второй раз ругается, что lcv2 принадлежит другому потоку. Как это победить?
ListCollectionView lcv2 = (ListCollectionView)CollectionViewSource.GetDefaultView(DataGrid.ItemsSource);
            if (_searchTextBoxText != null)
                lcv2.Filter = new Predicate<object>(FilterFields);
            else
                lcv2.Filter = null;
            DataGrid.Dispatcher.BeginInvoke(new Action(delegate
            {
                DataGrid.ItemsSource = lcv2;
            }));
  • Вопрос задан
  • 3622 просмотра
Пригласить эксперта
Ответы на вопрос 6
MikhailD
@MikhailD
Developer
Менять UI в потоках, отличных от UI-потока нельзя. Если вам нужно из другого потока изменить данные в UI, воспользуйтесь диспатчером

Пример того, как это выглядит в WinRT:
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    // Код, работающий в UI потоке
                });
Ответ написан
Комментировать
@serdceder
Создайте отдельный класс ViewModel, там создайте сво-во
public ListCollectionView SearchResults
{
get { return _searchResults2; }
set
{
_searchResults2 = value;
RaisePropertyChanged("SearchResults");
}
}

А это обработчик для команды:
...
_searchResults2.Dispatcher.BeginInvoke(
(Action)delegate
{
_searchResults2.Filter = new Predicate(o => ...)
}, System.Windows.Threading.DispatcherPriority.Background);
SearchResults = _searchResults2;

И будет вам счастье. Учитесь работать через команды и не совмещайте логику и View.
Ответ написан
Комментировать
@serdceder
А вы как хотели? Конечно интерфейс будет виснуть, вы напрямую с потоком UI работаете, коллекцию фильтруете на лету. Есть несколкьо атрофированный класс BackroundWorker, но лучше синхронизацией контекста воспользуйтесь - она позволяет передавать данный из одного потока в другой с помощью событий. Почитайте материал, там очень много теории.
Ответ написан
Комментировать
@Basterrior Автор вопроса
Спасибо за ответ, но мне это не помогает. С потоками-то понятно.
Тут дело в том, что в первый раз срабатывает так, как мне надо, а затем lcv2 передаётся под управление UI-потока. Нужно её как-то отвязывать и вообще избавиться от неё... она ведь определена только внутри функции и при следующем заходе должна как-то заново инициализироваться, а выходит, вроде, что lcv2.Filter = new Predicate(FilterFields); пытается работать со старой переменной и ему это не удаётся. Если поместить это в диспатчер, то смысл от фонового потока теряется и интерфейс будет тормозить.
Ответ написан
Комментировать
@Basterrior Автор вопроса
Можно как-то отвязать DataGrid.ItemsSource от ListCollectionView?
Как бы отменить DataGrid.ItemsSource = lcv2;.
Ответ написан
Комментировать
@Basterrior Автор вопроса
Пока всё же продолжу без MVVM.
Попробовал, как написано, только без MVVM:
Dispatcher.BeginInvoke(new Action(delegate
                    {
                lcv2.Filter = item =>
                {
                    int count = item.GetType().GetProperties().Count<object>();
                    bool result = false;
                    for (int i = 0; i < count; i++)
                        if (item.GetType().GetProperties()[i].GetValue(item, null).ToString().Contains(_searchTextBoxText))
                            result = true;
                    return result;
                };
                    }), System.Windows.Threading.DispatcherPriority.Background);

Не помогает, виснет интерфейс.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы