带有GUI接口的C#(WPF)异步线程

时间:2017-10-16 08:10:18

标签: c# wpf multithreading asynchronous

感谢您阅读此主题。

对于新的WPF应用程序(使用C#构建),我对设计有疑问。 过去几天我已经阅读了很多关于C#中的异步编程(基于.NET 4.5)。

我们想要做的是:创建一个新的异步线程,它执行独立的后台任务。当此线程有可用数据时:然后将此数据发送到主程序(通过公共接口)。因此,线程将在主程序中设置数据并立即再次返回到线程。当数据发生变化时,主程序将引发一个事件(INotifyPropertyChanged)。

创建此异步线程的最佳方法是什么?或者至少,设计此功能的最佳方法是什么?

目前我已经构建了一个创建线程的应用程序。 目前这不起作用Async:

    public MainWindow()
    {
        InitializeComponent();

        InitGuiInterface(this);

        //Create thread
        new OuterLabel_Thread(this);
    }

下面的课程“OuterLabel_Thread.cs”:

public class OuterLabel_Thread
{
    private MainWindow context = null;
    private bool exit = false;
    private int count = 0;

    public OuterLabel_Thread(MainWindow context)
    {
        this.context = context;

        Console.WriteLine("Running sample thread");
        Thread thread = new Thread(delegate ()
        {
            Console.WriteLine("Sample thread started");

            //start new task
            //run();
            Task.Factory.StartNew(run);
        });
        thread.Start();
    }

    public void Exit()
    {
        exit = true;
    }

    private void run()
    {
        while (!exit)
        {
            DateTime Time1 = DateTime.Now;

            if (context != null && context.GuiInterface != null)
            {
                //context.GuiInterface.UpdateThreadCount(count, "label_code_content");
            }
            Console.WriteLine("Background thread count = " + count);

            count++;
            if (count > 1000)
            {
                exit = true;
            }
            //Console.WriteLine((DateTime.Now - Time1).TotalMilliseconds.ToString());
            Thread.Sleep(10);
        }
    }
}

非常感谢提前! 亲切的问候,

3 个答案:

答案 0 :(得分:1)

因为你想保持线程活着,据我所知,你不确切知道何时或是否会达到1000分,异步可能是错误的选择。如果我错了,请纠正我。

对于您的情况,我建议使用BackgroundWorker:

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
   int count = 0;
   BackgroundWorker worker = sender as BackgroundWorker;
        while (!exit)
        {
            DateTime Time1 = DateTime.Now;
            worker.ReportProgress(count);
            count++;
            if (count > 1000)
            {
                exit = true;
            }
            Thread.Sleep(10);
        }
}

// This event handler updates the progress.
        private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            resultLabel.Text = ("Background thread count = " + e.ProgressPercentage.ToString());
        }

    private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled == true)
        {
            resultLabel.Text = "Canceled!";
        }
        else if (e.Error != null)
        {
            resultLabel.Text = "Error: " + e.Error.Message;
        }
        else
        {
            resultLabel.Text = "Done!";
        }
    }

答案 1 :(得分:1)

最好的方法是使用async + await和tasks。

    private async void LaunchButton_OnClick(object sender, RoutedEventArgs e)
    {
        resultLabel.Content = "Task running";
        resultLabel.Content = await SomeLongRunningTaskAsync();
    }

    private Task<string> SomeLongRunningTaskAsync()
    {
        return Task.Run(
            () =>
            {
                // Put your background work in here. with Task.Run it's not going to run on UI 
                int count = 0;
                while (count < 1000)
                {
                    count++;
                    Thread.Sleep(10);
                }

                return "Task done";
            });
    }

答案 2 :(得分:0)

我无法弄清楚你是在寻找服务还是长期任务。

由于其他人都有很好的长期任务示例,我已经提供了服务

它使用了一些高级内容,例如SynchronizationContext,您应该在生产代码中使用它之前阅读这些内容。 Google异步等待和Stephen Cleary。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var foo = new FooService();
        foo.StartService(); // UI thrad calling
    }
}

public class FooService
{
    private SynchronizationContext _context;
    private CancellationTokenSource _cts;
    private CancellationToken _token;
    private Task _task;

    public void StartService()
    {
        _context = SynchronizationContext.Current; // Depends on the UI thread being the one to start the service or this will fail
        _cts = new CancellationTokenSource(10000); // Run for 10 seconds
        _token = _cts.Token;
        _task = Task.Run(() => Run(), _token);
    }

    public async Task Stop()
    {
        _cts.Cancel();
        await _task; // wait for task to finish
    }

    private void Run()
    {
        while (!_token.IsCancellationRequested)
        {
            // Do work                
            Thread.Sleep(1000);
            // Alternative use Control.Invoke() if you have access to a UI element, to delegate to the UI thread
            _context.Send((id) => Console.WriteLine($"Delegate from thread {id} to thread {Thread.CurrentThread.ManagedThreadId}"), Thread.CurrentThread.ManagedThreadId);
        }
    }
}