Dispatcher.Dispatch在UI线程 [英] Dispatcher.Dispatch on the UI thread

查看:1087
本文介绍了Dispatcher.Dispatch在UI线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于何时使用Dispatcher.Invoke更新从不同的线程UI东西疑问。



下面是我的代码...

 公共Window4()
{
的InitializeComponent();
this.DataContext =这一点;

Task.Factory.StartNew(()=>试验());
}

私人列表<串GT; listOfString =新的List<串GT;();

公开名单<串GT; ListOfString
{
{返回listOfString; }
集合{listOfString =价值; }
}

公共无效测试()
{
listOfString.Add(ABC);
listOfString.Add(ABC);
listOfString.Add(ABC);
}

<网格和GT;
< ListView控件的ItemsSource ={结合ListOfString}/>
< /网格和GT;



我开始一个新的任务在不同的线程,做我需要使用Dispatcher.BeginInvoke更新用户界面。



在这种情况下,更新用户界面,但我见过一些情况下,人们更新UI使用Dispatcher.Invoke或BeginInvoke的从不同的线程。



所以我的问题是,当我们做到这一点,为什么在这种情况下,它工作正常。



谢谢&安培;问候,
BHavik


解决方案

我有一个关于何时使用调度员怀疑。调用更新来自不同线程UI
的东西。




当你在不同的线程,你将永远有使用调度更新属于另一个线程UI组件。




我在不同的线程开始一个新的任务,我是否需要使用
Dispatcher.BeginInvoke更新UI




任务允许多个操作不阻塞线程它们将被执行的从名为但这并不意味着他们是在不同的线程。更新从任务内的UI然而,当你需要使用的调度程序。




在这种情况下,正在更新的用户界面,但我见过一些情形
的人使用更新或Dispatcher.Invoke BeginInvoke的从
不同的线程UI。




调用将阻塞调用线程,而它正在执行的操作,而BeginInvoke不会。的BeginInvoke将立即返回控制给调用者,调用可能导致调用线程,如果它正在执行一项繁重的操作挂起。



这是从MSDN文档,




在WPF中,只有创建DispatcherObject访问
该对象的线程。例如,从$ B $分拆B中的主UI线程后台线程不能更新按钮,这是在UI线程上创建
的内容。为了使后台线程访问
按钮的内容属性,后台线程必须
代表与UI线程关联的工作分派。
这是通过使用Invoke或BeginInvoke来完成。 。调用是
同步和BeginInvoke是异步操作。




编辑:在回答你的评论我跑了一些测试。



当从一个任务调用测试()(不使用调度程序)我得到这个错误,因为不同的线程拥有它调用线程不能访问该对象。



所以,我创建了一个名为PrintThreadID()方法。我打印的线程从里面的任务进入任务,然后才和它同时报告都在相同的线程 ID上运行。



该错误是误导,因为它说,调用线程比拥有它该PrintThreadID()函数显示事实并非如此的不同,他们实际上是在同一个线程。任务,而在相同的线程仍然无法在不使用Dispather.Invoke更新UI组件()。



因此​​,这里是一个工作示例将更新从任务的网格。






 公共部分类主窗口:窗口
{
公开名单<串GT; myList中获得{;私人集; }

公共主窗口()
{
的InitializeComponent();
myList中=新名单<串GT;();
label1.Content = Thread.CurrentThread.ManagedThreadId.ToString();

Task.Factory.StartNew(PrintThreadID);
Task.Factory.StartNew(试验);

}

私人无效PrintThreadID()
{
label1.Dispatcher.Invoke(新动作(()=>
LABEL1 .Content + =...+ Thread.CurrentThread.ManagedThreadId.ToString()));
}

私人无效测试()
{
myList.Add(ABC);
myList.Add(ABC);
myList.Add(ABC);

//如果你不使用的调度员,你会得到错误调用线程不能因为不同的线程拥有它访问该对象。


dataGrid1.Dispatcher.Invoke(新动作(()=>
{
dataGrid1.ItemsSource = myList.Select(I =>新建项目{ = I});
}));
}
}


I have the doubt regarding when to use the Dispatcher.Invoke to update something on UI from different Thread.

Here's my code...

public Window4()
    {
        InitializeComponent();
        this.DataContext = this;

      Task.Factory.StartNew(() => Test() );
    }

    private List<string> listOfString = new List<string>();

    public List<string> ListOfString
    {
        get { return listOfString; }
        set { listOfString = value; }
    }

    public void Test()
    {
        listOfString.Add("abc");
        listOfString.Add("abc");
        listOfString.Add("abc");
    }

 <Grid>
    <ListView ItemsSource="{Binding ListOfString}" />
</Grid>

I am starting a new Task on the different Thread, do i need to use Dispatcher.BeginInvoke to update the UI.

In this case it is updating the UI, but i've seen some scenarios where people update UI using Dispatcher.Invoke or BeginInvoke from the different Thread.

So my question is when we have to do that and why in this case it is working fine.

Thanks & Regards, BHavik

解决方案

I have the doubt regarding when to use the Dispatcher.Invoke to update something on UI from different Thread.

When you are on a different thread you will always have to use the dispatcher to update a ui component that belongs to another thread.

I am starting a new Task on the different Thread, do i need to use Dispatcher.BeginInvoke to update the UI.

Tasks allow for multiple operations to be performed without blocking the thread they are called from but that doesn't mean they are on a different thread. However when updating the UI from inside a Task you will need to use the dispatcher.

In this case it is updating the UI, but i've seen some scenarios where people update UI using Dispatcher.Invoke or BeginInvoke from the different Thread.

Invoke will block the calling thread while it is performing the action and BeginInvoke will not. BeginInvoke will return control immediately to the caller, Invoke may cause the calling thread to hang if it is performing a heavy operation.

This is from msdn documentation,

In WPF, only the thread that created a DispatcherObject may access that object. For example, a background thread that is spun off from the main UI thread cannot update the contents of a Button that was created on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous.

Edit: In response to your comment I ran some tests.

When calling Test() from a task (without using the dispatcher) I got this error "The calling thread cannot access this object because a different thread owns it."

So I created a method called PrintThreadID(). I printed the thread before entering the task then from inside the task and it does report both are running on the same thread ID.

The error is misleading because it says the calling thread is different than the one that owns it which the PrintThreadID() function shows is not true, they are in fact on the same thread. Tasks while on the same thread still cannot update a UI component without using Dispather.Invoke().

So here is a working example which will update the Grid from a task.


public partial class MainWindow : Window
{
    public List<string> myList { get; private set; }

    public MainWindow()
    {
        InitializeComponent();
        myList = new List<string>();
        label1.Content = Thread.CurrentThread.ManagedThreadId.ToString();

        Task.Factory.StartNew(PrintThreadID);
        Task.Factory.StartNew(Test);

    }

    private void PrintThreadID()
    {
        label1.Dispatcher.Invoke(new Action(() =>
            label1.Content += "..." + Thread.CurrentThread.ManagedThreadId.ToString()));
    }

    private void Test()
    {
        myList.Add("abc");
        myList.Add("abc");
        myList.Add("abc");

        // if you do not use the dispatcher you will get the error "The calling thread cannot access this object because a different thread owns it."


        dataGrid1.Dispatcher.Invoke(new Action(() =>
        {
            dataGrid1.ItemsSource = myList.Select(i => new { Item = i });
        }));
    }
}

这篇关于Dispatcher.Dispatch在UI线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆