【问题标题】:A very basic explanation for threading in WPF?WPF中线程的一个非常基本的解释?
【发布时间】:2011-12-29 07:37:47
【问题描述】:

我对 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:你在编程上想的太多了。总结是,我想在后台做一些繁重的任务,并在主窗口中显示它的进度。无论如何,谢谢你的建议。我实际上不想显示查询更新消息,即使是单个查询。
  • Google 并了解:System.Threading.SynchronizationContext.Current。

标签: c# .net wpf multithreading


【解决方案1】:

您需要将 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
  }

【讨论】:

  • 怎么样?请用代码告诉我!包含我需要调用的所有命名空间和类!
  • 这将如何编译?
  • 什么意思?该代码Set initial... 只是代表一些真实的代码
  • @HarisHasan:如果我想在后台线程中添加一些 UI 怎么办。
  • 为此发布一个单独的问题
【解决方案2】:
  1. 多线程无法处理您选择的 UI 技术(Wpf 或 Winforms) - 当您必须切换到 UI 线程来更新您的控件时,只有细微的差别。

  2. 根据您的代码示例,我必须说,从 sql server 到您的程序没有回调的可能性。如果你想拥有那个特性,你必须在 C# 中而不是在 sql 语句中实现循环。

编辑:

根据 OP 的评论,我使用TPL (Task Parallel Library) 在前台添加了后台工作和更新 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();

【讨论】:

  • 这只是一个例子。对于不同的场景,你能告诉我另一种方式吗?例如,使用标签“正在搜索...”搜索非常大的 LIST,并在找到时将其关闭。任何示例都只是让我知道最基本的方法。
  • @user995387:根据您的评论,我在答案中添加了一个示例。
  • 我不能在任务中创建新的用户界面(网格)吗?请阅读我更新后的查询!
  • @user995387:对于未来,请记住:对于新问题,提出新问题!你得到那个错误,因为你想在后台任务中创建一个网格,这是不可能的。您必须在 UI 线程中执行此操作。但是,如果您将任务切换到 UI 线程,您将不会有任何“多线程”优势,因为此时线程正在“前台”运行。
  • hmm ...我开始了新线程:stackoverflow.com/questions/8667529/… 我不能创建一个不同的 UI 线程来创建 UI 或流文档并在后台线程中使用它吗?
【解决方案3】:

这是处理 WPF 线程的示例代码 sn-p..

考虑这种情况。

我们必须从服务器获取一些数据,然后我们才能玩数据。 意味着我们接下来的动作完全依赖于Task的回调或者完成。

在这种情况下,我们可以使用任务工厂的 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
    });
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多