感谢您阅读此主题。
对于新的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);
}
}
}
非常感谢提前! 亲切的问候,
赖
答案 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);
}
}
}