WPF中线程的基础解释是什么?

4

我对WPF非常陌生。我在互联网上查找了一些关于线程的示例和教程,它们都有自己的描述方式。但对像我这样的新手来说,我想用自己的方式理解。

我可以通过数据库更新功能开始我的第一个线程。

以下是场景:

我有大量数据要插入数据库。现在让我们假设以下代码(此过程将在我点击“继续”按钮后启动):

int initial = 0;
int maxData = 10
while (initial<maxData) {
   //Database query here
}

上述过程将在不同的线程中运行。

接下来,在我的主窗口中有一个“标签”。对于每个数据库查询,我想在标签中显示一些消息。

例如:

// this will happen in default UI thread.
label.Content = "Updating"; // Specifically for @TomTom ;)

编辑:

我已经完成了以下操作:
var task = new Task(() =>
    {
       for (int i=0; i<10; i++) {
          //Create new Grid HERE
          // Add Table with some dynamic data here..
          // print the above Grid here.
        }

    });

task.ContinueWith((previousTask) =>
    {
        label.Content = printerStatus(); // will return "Out of Paper", "printing", "Paper jam", etc.
    },
    TaskScheduler.FromCurrentSynchronizationContext());

label.Content = "Sending to printer";

程序会返回错误,显示“调用线程必须为STA,因为许多UI组件需要此线程类型”。 我不知道接下来该怎么办,请帮忙!

@TomTom: 你过于注重编程方面的思考。总结来说,我想在后台执行一些繁重的任务,并在主窗口中显示它的进度。 无论如何,感谢你的建议。实际上,我不想显示查询更新消息,甚至不想显示单个查询的更新消息。 - user995387
请搜索并学习:System.Threading.SynchronizationContext.Current。 - Rick2047
3个回答

13
你需要使用BackgroundWorker来处理长时间运行的任务,并使用Dispatcher在其中更新UI。
 //create background worker
 BackgroundWorker worker = new BackgroundWorker();
 //assign it work
 worker.DoWork += new DoWorkEventHandler(worker_DoWork);
 //start work
 worker.RunWorkerAsync();


//this work will be done in background
void worker_DoWork(object sender, DoWorkEventArgs e)
{
    SET initial = 0;
    SET maxData = 1000
    DO UNTIL initial <1000
   CREATE db query "INSERT INTO (col1,col2,col3) VALUES(value1,value2,value3);"

   //in between your work do this to update label
   label.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,new Action(delegate()
        {
         Label.Content = "SomeValue";
        }
        ));
   END DO
  }

怎么做?请用代码展示给我看!请包含我需要调用的所有命名空间和类! - user995387
这怎么可能编译通过? - Emond
1
你是什么意思?那段代码 Set initial... 只是代表一些真实的代码。 - Haris Hasan
@HarisHasan:如果我想在后台线程中添加一些UI怎么办? - user995387
为此请发布一个单独的问题。 - Haris Hasan
@HarisHasan: 希望你能在这里给些建议.... http://stackoverflow.com/questions/8667529/creating-a-ui-in-background-thread-wpf - user995387

3
  1. 多线程与您选择的 UI 技术(Wpf 或 Winforms)无关 - 当您需要切换到 UI 线程以更新控件时,只有轻微的差异。

  2. 根据您的代码示例,我必须说,没有从 SQL Server 回调到您的程序的可能性。如果您想要该功能,则必须在 C# 中实现循环,而不是在 sql 语句中。

编辑:

根据 OP 的评论,我添加了一个使用 TPL(任务并行库) 在后台工作并在前台更新 UI 的示例:

var task = new Task(() =>
    {
        // Do something very long ...
    });

task.ContinueWith((previousTask) =>
    {
        label.Content = "Background work has finished.";
    },
    TaskScheduler.FromCurrentSynchronizationContext());

label.Content = "Background work is running.";
task.Start();

那只是一个例子而已。你能为不同的情况给我展示另一种解决方法吗?比如,搜索带有标签“searching...”的极大列表,并在找到后关闭它。任何例子都可以,只要让我知道最基本的做法即可。 - user995387
根据您的评论,我在我的答案中添加了一个示例。 - Fischermaen
我无法在任务中创建新的用户界面(网格)吗?请阅读我的更新查询! - user995387
@user995387:请记住,对于新问题,请提出新的问题!您会收到该错误,因为您想在后台任务中创建网格,这是不可能的。您必须在UI线程中执行此操作。但是,如果您将任务切换到UI线程,则不会有任何“多线程”优势,因为此时线程正在“前台”运行。 - Fischermaen
嗯...我开始了一个新线程:http://stackoverflow.com/questions/8667529/creating-a-ui-in-background-thread-wpf我不能创建一个不同的UI线程来创建UI或FlowDocument,然后在后台线程中使用它吗? - user995387

1

这里是处理WPF线程的示例代码片段。

考虑以下情况。

我们需要从服务器获取一些数据,之后我们需要对数据进行操作。 也就是说,我们的下一个动作完全取决于任务的回调或完成。

在这种情况下,我们可以使用任务工厂的ContinueWith方法,如下所示:

ObservableCollection images = new ObservableCollection();
TaskFactory tFactory = new TaskFactory();
tFactory.StartNew(() =>
{
    for (int i = 0; i < 50; i++)
    {
    //GET IMAGE Path FROM SERVER
        System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)delegate()
        {
        // UPDATE PROGRESS BAR IN UI
        });    
    images.Add(("");
    }

}).ContinueWith(t =>
{
    if (t.IsFaulted)
    {
        // EXCEPTION IF THREAD IS FAULT
        throw t.Exception;
    }
    System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)delegate()
    {
        //PROCESS IMAGES AND DISPLAY
    });
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接