tags:

views:

182

answers:

4

I added an event handler to my code and it broke all access to the CollectionViewSources in the SystemHTA class saying "The calling thread cannot access this object because a different thread owns it". My class was working when "this.systemHTA = new SystemHTA();" was placed outside of the DeviceManager_StateChanged() function.

    public partial class MainWindow : Window
    {
        private DeviceManager DeviceManager = DeviceManager.Instance;
        public SystemHTA systemHTA;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            DeviceManager.StateChanged += new EventHandler<DeviceManagerStateChangedEventArgs>(DeviceManager_StateChanged);
            DeviceManager.Initialize();
        }

        void DeviceManager_StateChanged(object sender, DeviceManagerStateChangedEventArgs e)
        {
            if (e.State == DeviceManagerState.Operational)
            {
                this.systemHTA = new SystemHTA();
            }
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this.systemHTA.GetViewSourceTest();
        }
    }


    public class SystemHTA
    {
        private CollectionViewSource _deviceTestSource;

        public SystemHTA()
        {
            _deviceTestSource = new CollectionViewSource();
            _deviceTestSource.Source = CreateLoadData<HWController>.ControllerCollection;
        }

        public void GetViewSourceTest()
        {
            ListCollectionView view = (ListCollectionView)_deviceTestSource.View; //This creates an error saying a thread already owns _deviceTestSource
        }
    }
A: 

What you're looking for here is Dispatcher.BeginInvoke. Have a look here for a complete explanation:

Dispatcher.BeginInvoke

Here is some more concrete help to get you going as well:

Working with the WPF dispatcher

Good luck.

byte
Just as an aside you may want to look into databinding to help with the situation. Databinding automatically goes through the Dispatcher.
Agies
A: 

Here is some sample code that will solve your problem using Invoke: cross thread operation not valid. You need to access the information from the creating thread.

Dan
A: 

Ok, CollectionViewSource derived classes, BindableList, ObservableCollection etc these classes can only be created in main dispatcher thread only.

However you have to try something of following sort, Create your collectionviewsource only in your WPF derived classes, use List<> classes to load your objects in different thread and once done, you can transfer from list to collectionviewsource as follow, I would recommend BindingList because you can add multiple items disabling the refresh to remove flickering.

Create your collection object implicitly in your WPF classes as follow

public class MyWindow : UserControl{
BindingList<MyObject> ObjectList = new BindingList<MyObject>;
    public MyWindow(){
        ObjectList.AllowAdd = true;
        ObjectList.AllowDelete = true;
        ObjectList.AllowEdit = true;
    }
    public void LoadObjects(){
       ThreadPool.QueryUserItem( (s)=>{
           // load your objects in list first in different thread
           List<MyObject> list = MyLongMethodToLoadObjects();
           Dispatcher.BeginInvoke( (Action)delegate(){
               list.RaiseEvents = false;
               foreach(MyObject obj in list){
                   ObjectList.Add(obj);
               }
               list.RaiseEvents = true;
               list.ResetBindings();
           });
       });
    }
}

I dont know this code does not format correctly but you may try seeing it in visual studio to get correct idea.

Akash Kava
I ended up just replacing CollectionViewSource with ObservableCollection and everything works fine. Thanks for pointing me in the right direction.
Robert
A: 

Simple and stable solution for you is to use BackgroundWorker. Read this article BackgroundWorker

Daniel Bern