3

I'm trying to generate and dispatch (while having my UI Thread with progressRing.IsActive = true;), three List Objects on a BackgroundWorker and then transfer said list to the UI Thread, but I'm running into issues with...

Must create DependencySource on same Thread as the DependencyObject.

Resources, I've read

Method BackgroundLogin() of Partial Class MainWindow

    private void BackgroundLogin()
    {
        //process the form on UI Thread
        this.LoginForm(FadeOut);
        this.LoadingRing(FadeIn);

        //Start a new Thread
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        //initialize custom class WorkerThread object to store/process a result
        WorkerThread wt = new WorkerThread(this, txtEmailAddress.Text, txtPassword.Password);
        //start the worker and send the object across.
        worker.RunWorkerAsync(wt);
    }

Method worker_DoWork of Partial Class MainWindow

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //grab the object
        WorkerThread wt = (WorkerThread)e.Argument;
        //check if we can login
        if (!wt.Login())
        {
            //cancel the thread
            e.Cancel = true;
        }
        else
        {
            //load additional data
            wt.UpdateAuthLbl(".. Loading New Data ..");
            wt.LoadLists();
            wt.UpdateAuthLbl(".. Data Loaded ..");
        }
        //pass the object back
        e.Result = wt;
    }

Method loadLists() of Class WorkerThread

    /// <summary>
    /// Load data into the list
    /// </summary>
    public void LoadLists()
    {
        this.gene_fact_list = db.loadGeneFactTable();
        this.gene_trait_fact_list = db.loadGeneTraitFactTable(this.gene_fact_list);
        this.category_trait_list = db.loadCategoryTraits();
    }

Method worker_RunWorkerCompleted of Partial Class MainWindow, Object gl of Class GeneList

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //grab the finished object
        WorkerThread wt = (WorkerThread) e.Result;
        //work out if we are logged in
        Boolean LoginFlag = !e.Cancelled && e.Error == null;
        if (LoginFlag)
        {
            lblAuthentication.Content = ".. Loading Interface ..";
            //pass the finished object into memory
            this.gl = wt;
            //reset the listbox
            this.resetListBox();
        }
        this.LoginForm(LoginFlag);
    }

Method resetListBox() and ListBoxItems

    /// <summary>
    /// Load the data for the form
    /// </summary>
    public void resetListBox()
    {
        if (this.gl.notNullOrEmpty())
        {
            this.ListBoxItems.Clear();
            //begin compiling the mainTab
            foreach (KeyValuePair<long, GeneNotesDataModel> kvp in this.gl.gene_fact_list)
            {
                this.ListBoxItems.Add(kvp.Value);
            }
        }
    } //close function

    //declare WPF list binding
    private ObservableCollection<GeneNotesDataModel> _listBoxItems = new ObservableCollection<GeneNotesDataModel>();

    /// <summary>
    /// Control the listbox of rsid codes
    /// </summary>
    public ObservableCollection<GeneNotesDataModel> ListBoxItems
    {
        get { return _listBoxItems; }
        set { _listBoxItems = value; }
    }

XAML ListBox lstSnpCodes

<ListBox ItemsSource="{Binding ElementName=UI, Path=ListBoxItems}" Margin="6,38,0,60" BorderThickness="2" HorizontalAlignment="Left" Width="180" Name="lstSnpCodes" SelectionChanged="lstSnpCodes_SelectionChanged" KeyUp="OnKeyUpHandler" />

The line this.ListBoxItems.Add(kvp.Value); causes the Exception to occur (If I replace it with Debug.WriteLine(kvp.Value.getValueAsString()); it will run just fine). Any ideas on why I'm getting a DependencySource exception? and why isn't possible to transfer ListA from Slave Thread to Main Thread?

PasteBin Links expire in April 2013

Community
  • 1
  • 1
classicjonesynz
  • 4,012
  • 5
  • 38
  • 78
  • Is gene_fact_list a property or an exposed field? If it is a property, you can only do this on the main thread (AFAIK). Perhaps what you need is an accessor method (like Set_gene_fact_list(list lst). – William Mar 04 '13 at 01:33
  • Also, remember to use either a mutex or some kind of readonly object for locking purposes to sync read/write operations to the list. – William Mar 04 '13 at 01:39
  • @William all three lists are properties of the `MainWindow.xaml` (or `MainWindow window`), I've tried using a Setter, but I had the same issue. So the current snippet is using the `{get;set;}` to update the list in `window`. – classicjonesynz Mar 04 '13 at 01:41
  • @William can you please add that an answer? (with detail about [Task](http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx) preferably I would like the `db` methods to be accessed via the `Task`) – classicjonesynz Mar 04 '13 at 02:23
  • 1
    Go through a similar issue http://stackoverflow.com/questions/12554612/must-create-dependencysource-on-same-thread-as-the-dependencyobject-when-creat – Sakthivel Mar 05 '13 at 10:22

1 Answers1

1

Instead of trying to access the property directly across threads, try accessing the variable behind it.

In sample app:

private static List<object> _lst;


    static void Main(string[] args)
    {
        Task tsk =  new Task(() => _lst = new List<object>()); //task will create new thread if available and execute the Action.
        tsk.Start(); //initiates task, which initiates new List<object> on new thread.
        tsk.Wait(); //waits for task to complete.  Note that this locks main thread.
        _lst.Add(1); //Attempt to access _lst from main thread.
    }

Specific to your example.

private ReadOnly object _lockMyList = new object();
private List _MyList;

public void SetMyList(List lst) //Use this to set list from other thread.
{
    Lock(_lockMyList)
    {
        _MyList = lst;
    }
    //Invoke Property Changed event if needed for binding.
}

public List MyList
{
    get
    {
        List lst = null;
        Lock(_lockMyList)
        {
            lst = _MyList; //You might need to do _MyList.ToList() for true thread safety
        }
        return lst;
    }
    //Property setter if needed, but use accessor method instead for setting property from other thread
}

Also, you may want to look into SynchronizedCollection to see if it is more suitable for your needs.

I hope this helps.

William
  • 551
  • 2
  • 10
  • 24
  • Regarding Task just search for Task Parallel Library. In my opinion it is easier to use Tasks then managing threads directly (as long as you don't need to set STAThread). Also, remember that whatever you do to your UI will need to be done on the Dispatcher thread. – William Mar 04 '13 at 06:29
  • I've tried your solution but I'm still getting errors :-/, I added the locks into [`GeneList`](http://pastebin.com/2Xp69NvY) and modified the method `loadLists` to take advantage of locking to stop `Race Conditions`, but the exception `Must create DependencySource on same Thread as the DependencyObject.` is still active. – classicjonesynz Mar 05 '13 at 02:28
  • Decided just to use `this.Dispatcher.Invoke((Action)` with some locks, thanks William – classicjonesynz Mar 06 '13 at 02:34
  • 1
    Okay. If you use Dispatcher.Invoke(/*Some kind of Action delegate*/), all you are doing is invoking on the main thread, so it may or may not be what you want depending on where you put the invoke. Also, when using invoke, be careful not to create conditions where the application would lock. Finally, if you are using the setter accesssor method, and the setter accessor method is writing to the private list (i.e. not trying to access the property), then you should not be receiving this error provided the class itself is owned by the dispatcher thread. I hope that all makes sense. – William Mar 07 '13 at 19:58
  • 1
    Also, I would strongly recommend looking into the SynchronizedCollection class, which is basically an ICollection that provides multi-threaded support. – William Mar 07 '13 at 19:59