【问题标题】:why isn't possible to transfer ListA from Slave Thread to Main Thread?为什么不能将 ListA 从从属线程转移到主线程?
【发布时间】:2013-02-18 00:37:31
【问题描述】:

我正在尝试生成和分派(同时让我的 UI 线程使用progressRing.IsActive = true;),三个List 对象位于BackgroundWorker 上,然后将所述列表传输到UI Thread,但我遇到了问题...

Must create DependencySource on same Thread as the DependencyObject.

资源,我已阅读

部分类MainWindow的方法BackgroundLogin()

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

部分类MainWindow的方法worker_DoWork

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

部分类MainWindow的方法worker_RunWorkerCompleted,类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; }
    }

XAMLListBoxlstSnpCodes

<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 月到期

【问题讨论】:

  • gene_fact_list 是属性还是暴露字段?如果它是一个属性,则只能在主线程 (AFAIK) 上执行此操作。也许您需要的是访问器方法(例如 Set_gene_fact_list(list lst)。
  • 另外,请记住使用互斥锁或某种只读对象来锁定目的,以将读/写操作同步到列表。
  • @William 所有三个列表都是MainWindow.xaml(或MainWindow window)的属性,我尝试过使用Setter,但我遇到了同样的问题。所以当前的sn-p是使用{get;set;}更新window中的列表。
  • @William 你能补充一个答案吗? (最好有关于Task 的详细信息,我希望通过Task 访问db 方法)

标签: c# wpf multithreading dependencies backgroundworker


【解决方案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 以查看它是否更适合您的需求。

我希望这会有所帮助。

【讨论】:

  • 关于任务只需搜索任务并行库。在我看来,使用任务比直接管理线程更容易(只要您不需要设置 STAThread)。另外,请记住,您对 UI 所做的任何事情都需要在 Dispatcher 线程上完成。
  • 我已经尝试过您的解决方案,但我仍然遇到错误:-/,我将锁添加到 GeneList 并修改了方法 loadLists 以利用锁定来停止 Race Conditions ,但 Must create DependencySource on same Thread as the DependencyObject. 异常仍然有效。
  • 决定只使用带有一些锁的this.Dispatcher.Invoke((Action),谢谢William
  • 好的。如果你使用 Dispatcher.Invoke(/*Some kind of Action delegate*/),你所做的只是在主线程上调用,所以它可能是也可能不是你想要的,这取决于你把调用放在哪里。此外,在使用调用时,请注意不要创建应用程序将锁定的条件。最后,如果您正在使用 setter accesssor 方法,并且 setter accessor 方法正在写入私有列表(即不尝试访问属性),那么您不应该收到此错误,前提是类本身由调度程序线程拥有.我希望一切都有意义。
  • 另外,我强烈建议您研究 SynchronizedCollection 类,它基本上是一个提供多线程支持的 ICollection
猜你喜欢
  • 1970-01-01
  • 2016-03-25
  • 2015-02-03
  • 1970-01-01
  • 2020-02-20
  • 2020-05-23
  • 2012-06-19
  • 2014-08-04
  • 1970-01-01
相关资源
最近更新 更多