简体   繁体   中英

C# (WPF) Async Thread with interface to GUI

thanks for reading this topic.

For a new WPF application (build in C#) I have a question regarding the design. The past few days I have read a lot about Async programming in C# (based on .NET 4.5).

What we would like to do is: Create a new async thread, which does independent background tasks. When this thread has data available: then send this data to the main program (by an public interface). So, the thread will set data in the main program and immediately return to the thread again. The main program will raise an event (INotifyPropertyChanged) when data has been changed.

What will be the best way to create this Async thread? Or at least, what would be the best way to design this feature?

At the moment I have build an application which creates a thread. This does not work Async at the moment:

    public MainWindow()
    {
        InitializeComponent();

        InitGuiInterface(this);

        //Create thread
        new OuterLabel_Thread(this);
    }

And the class "OuterLabel_Thread.cs"here below:

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

Many thanks in advance! Kind regards,

Rein.

as you want to keep the thread alive and as far as I understand, you don't know exactly when or if you will reach the 1000 mark, async might be the wrong choice. Correct me if i'm wrong.

For your case I would recommend using the 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!";
        }
    }

The best way would be using async+await and 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";
            });
    }

I can't figure out if you are looking for a service or a long running task.

Since the others have good examples of long running tasks I've made a Service

It uses some advanced concpets like SynchronizationContext that you should read up on before using this in production code. Google async await and 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);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM