views:

1149

answers:

4

Hi. Is there any way how to do

ICollectionView.Refresh()

or

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

in a separate thread?

I know I can use dispatcher, but this collection is binded to a ListView and it throws cross thread Exceptions.

The reason why I need a second thread is, that I have Control which displays a list of IMyItems. When filtering this Collection (by user text change input), I want to be able to display my animation that CollectionView is changing.

A: 

I hacked up a quick method to invoke actions on wpf dispatchable objects (all wpf controls inherit from 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);
    }
}

Usage:

InvokeWpf(listView, 
       () => CollectionViewSource.GetDefaultView(listView).Refresh(), 
       false);
kek444
I tried your solution (I've made what you propose).. but anyhow it is running in the same thread...
PaN1C_Showt1Me
A: 

How about using the Dispatcher to do work with background priority?

Dispatcher.Invoke(DispatcherPriority.Background,
    () => { CollectionViewSource.GetDefaultView(args.NewValue).Refresh(); }
);
Arcturus
but that new value is binded to the ListView.. won't it throw an Exception? that this thread is not the owner?
PaN1C_Showt1Me
Well this solution is really working, You just have to be sure that while runing you don't call it again.. you must wait
PaN1C_Showt1Me
Thats true ;) but patience is a virtue they say ;)
Arcturus
Wow, I didn't know that was possible. That's good to know. +1 from me.
Botz3000
The dispatcher does not execute code in a background thread. It executes code in the main thread. The Background priority does not mean Background Thread. It means the code will be executed in the main thread when the main thread is not too busy. If the code you push in the dispatcher is long to execute, it will freeze the UI for the time it executes.Use the BackgroundWorker to execute code in threads.
decasteljau
Yes he is right.. it seemed that it works, but Invoke is synchronous.. with that background priority that means, that if i set a gray background while before Refresh(), it works because it has a higher priority. But if I choose an animation, it loads and freezes for the single thread reason.
PaN1C_Showt1Me
A: 

Well I tried this:

private static void ItemsSourcePropertyChangedCallback(DependencyObject controlInstance, DependencyPropertyChangedEventArgs args)
{
    /* args.NewValue is that IEnumerable Source Collection */
    (controlInstance as ListPicker).view = CollectionViewSource.GetDefaultView(args.NewValue);
}

private void txtSearch_TextChanged(object sender, TextChangedEventArgs e)
        {
            string filterText = (sender as TextBox).Text;

            txtSearch.Background = Brushes.Red;

            view.Filter = delegate(object obj)
            {
                if (String.IsNullOrEmpty(filterText))
                    return true;

                ICustomListItem item = obj as ICustomListItem;
                if (String.IsNullOrEmpty(item.Text))
                    return false;

                int index = item.Text.IndexOf(
                    filterText,
                    0,
                    StringComparison.InvariantCultureIgnoreCase);

                return index > -1;
            };

            InvokeWpf(lBox,
               () => view.Refresh(),
               false);

            txtSearch.Background = Brushes.LightBlue;              
        }

And it is synchronous.. What am I doing wrong? (The Red background color does not appear)

PaN1C_Showt1Me
First of all, why do you need a second thread? What threads are in this case? And what's the problem with colors here? You set the Background to Red and then immediately to LightBlue?
kek444
The reason why I need a second thread is, that I have Control which displays a list of IMyItems. When filtering this Collection, I want to be able to display my animation that CollectionView is changing.
PaN1C_Showt1Me
+2  A: 

You can't!

All UI operations must happen on the user interface thread, and nearly every call inside of WPF's DispatcherObject (and all controls in that hierarchy) are regularly going to be calling CheckAccess().

You might want to consider using an ObservableCollection to help keep your data up-to-date, if you're doing processing in a background thread or BackgroundWorker.

Jeff Wilcox
OK so the only way to do this is to have an ObservableCollection, that will processed in a background thread? Not the CollectionView!
PaN1C_Showt1Me