为什么不能将ListA从Slave Thread转移到主线程?

时间:2013-03-04 00:46:53

标签: c# wpf multithreading dependencies backgroundworker

我正在尝试生成和发送(使用progressRing.IsActive = true;的UI线程),List上的三个BackgroundWorker对象,然后将所述列表转移到UI Thread },但我遇到了......的问题。

  

Must create DependencySource on same Thread as the DependencyObject.

资源,我已阅读

部分班级BackgroundLogin()的方法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);
    }

部分班级worker_DoWork的方法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;
    }

WorkerThread的方法loadLists()

    /// <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();
    }

分类worker_RunWorkerCompleted的方法MainWindow,类GeneList的对象gl

    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);
    }

方法resetListBox()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" />

this.ListBoxItems.Add(kvp.Value);会导致Exception发生(如果我将其替换为Debug.WriteLine(kvp.Value.getValueAsString());,它就会运行得很好)。关于为什么我得到DependencySource异常的任何想法?为什么无法将ListASlave Thread转移到Main Thread

PasteBin链接将于2013年4月到期

1 个答案:

答案 0 :(得分:1)

不要尝试直接跨线程访问属性,而是尝试访问它后面的变量。

在示例应用中:

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.
    }

特定于您的示例。

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
}

此外,您可能需要查看SynchronizedCollection以查看它是否更适合您的需求。

我希望这会有所帮助。

相关问题