2009-08-05 2 views
1

Есть ли способ, как сделатьWPF ICollectionView Refresh

ICollectionView.Refresh() 

или

CollectionViewSource.GetDefaultView(args.NewValue).Refresh(); 

в отдельном потоке?

Я знаю, что я могу использовать диспетчер, но эта коллекция привязана к ListView, и она выдает исключение перекрестных потоков.

Причина, по которой мне нужен второй поток, заключается в том, что у меня есть элемент управления, который отображает список IMyItems. При фильтрации этой коллекции (по изменению ввода текста пользователя) я хочу иметь возможность отображать мою анимацию, которую CollectionView меняет.

+0

Если вы хотите отфильтровать это во время ввода пользователем, вы должны иметь возможность отображать свою анимацию (например, начать раскадровку), когда они начнут печатать - нет необходимости в втором потоке. –

ответ

3

Вы не можете!

операции Всех UI должны происходить на интерфейсном потоке пользователя, и почти каждый вызов внутри DispatcherObject WPF (и все элементы управления в этой иерархии) регулярно собираемся называть CheckAccess().

Возможно, вы захотите использовать ObservableCollection, чтобы поддерживать ваши данные в актуальном состоянии, если вы выполняете обработку в фоновом потоке или BackgroundWorker.

+0

Итак, единственный способ сделать это - иметь ObservableCollection, который будет обрабатываться в фоновом потоке? Не CollectionView! –

+0

Изменение коллекции bbservable на фоновом потоке будет STILL, потому что ваш сборщик будет отображаться поп ... – Gusdor

-2

я изрубил быстрый метод для вызова действия на МОФ диспетчерируемых объектов (все элементы управления WPF наследует от DispatcherObject)

public static void InvokeWpf(DispatcherObject dispatchable, Action action, bool async) 
{ 
    // DispatcherOperationCallback is optimized for wpf invoke calls 
    DispatcherOperationCallback toDo = delegate{ action(); return null; }; 

    if (!dispatchable.CheckAccess()) 
    { 
     if (async) 
      dispatchable.Dispatcher.BeginInvoke(toDo, null); 
     else 
      dispatchable.Dispatcher.Invoke(toDo, null); 
    } 
    else 
    { 
     toDo(null); 
    } 
} 

Использование:

InvokeWpf(listView, 
     () => CollectionViewSource.GetDefaultView(listView).Refresh(), 
     false); 
+0

Я пробовал ваше решение (я сделал то, что вы предлагаете) .. но так или иначе он работает в одном потоке ... –

+1

Как оптимизировать DispatcherOperationCallback? Это просто делегат. Поскольку у вас уже есть этот «действительный» делегат, перенос его в другой делегат - это просто пустая трата пространства и удобочитаемости. –

3

Как об использовании Диспетчера, чтобы сделать работу с приоритет фона?

Dispatcher.Invoke(DispatcherPriority.Background, 
    () => { CollectionViewSource.GetDefaultView(args.NewValue).Refresh(); } 
); 
+0

, но это новое значение привязано к ListView .. разве это не исключение? что эта нить не является владельцем? –

+0

Ну, это решение действительно работает, вам просто нужно быть уверенным, что при запуске вы не вызываете его снова .. вы должны подождать –

+0

Thats true;) но терпение - это добродетель, который они говорят;) – Arcturus