C#异步/等待写入文本框
不用说,我是C#新手,在学习过程中会做一些基本的事情。我试图理解异步/等待特性。我有一个带有两个文本框和一个按钮的表单。当我单击该按钮时,它会检查远程计算机的服务状态(在本例中为远程注册表)。在检查时,它会写入正在检查注册表并告诉用户等待。然后,如果状态已停止,则会启动,并获取我要查找的一些值,并将这些值写入第二个文本框 我的代码可以工作,并且我能够获得我的值。但是GUI在此期间冻结。我尝试实现backgroundworker、thread和Async/Wait,但没有成功。我尝试执行任务,但无法实现 当我试图返回一个字符串,将状态和值写入文本框时,这里或其他站点上显示的所有示例都只返回int。我试图将其转换为字符串,但没有成功 长话短说,对于这种类型的流程,什么是更好的方法?有人能告诉我如何和评论什么是我更好理解的方法吗?我想学习如何做到这一点,但同时学习为什么,并学习编写更干净的代码 感谢大家提前抽出时间C#异步/等待写入文本框,c#,multithreading,async-await,backgroundworker,C#,Multithreading,Async Await,Backgroundworker,不用说,我是C#新手,在学习过程中会做一些基本的事情。我试图理解异步/等待特性。我有一个带有两个文本框和一个按钮的表单。当我单击该按钮时,它会检查远程计算机的服务状态(在本例中为远程注册表)。在检查时,它会写入正在检查注册表并告诉用户等待。然后,如果状态已停止,则会启动,并获取我要查找的一些值,并将这些值写入第二个文本框 我的代码可以工作,并且我能够获得我的值。但是GUI在此期间冻结。我尝试实现backgroundworker、thread和Async/Wait,但没有成功。我尝试执行任务,但无
string ComputerName = "Lab01";
public frmRegChecker()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
Check_Status();
}
private void Check_Status()
{
TxtBoxstatus.AppendText("Checking Remote Registry service status on computer : " + ComputerName);
TxtBoxstatus.AppendText(Environment.NewLine);
TxtBoxstatus.AppendText("Please wait... ");
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
try
{
TxtBoxstatus.AppendText("The Remote Registry service status is currently set to : " + sc.Status.ToString());
TxtBoxstatus.AppendText(Environment.NewLine);
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
TxtBoxstatus.AppendText("Starting Remote Registry service...");
TxtBoxstatus.AppendText(Environment.NewLine);
try
{
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
// Display the current service status.
TxtBoxstatus.AppendText("The Remote Registry status is now set to:" + sc.Status.ToString());
richTextBox1.AppendText(Environment.NewLine);
try
{
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\");
string _OSVersion = (key.GetValue("CurrentVersion")).ToString();
richTextBox1.AppendText("OS version is : " + _OSVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Could not start the Remote Registry service.");
richTextBox1.AppendText(Environment.NewLine);
}
}
else if (sc.Status == ServiceControllerStatus.Running)
{
try
{
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\");
string _OSVersion = (key.GetValue("CurrentVersion")).ToString();
richTextBox1.AppendText("OS version is : " + _OSVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
}
}
catch
{
richTextBox1.AppendText("Error getting registry value from " + ComputerName);
richTextBox1.AppendText(Environment.NewLine);
}
}
我认为您仍然可以使用backgroundworker在不冻结GUI的情况下使文本框显示消息。请参考此问题,了解如何从backgroundworker返回对象。这可以使用async/Wait轻松完成。例如: 一个简单的WPF表单:
<Window x:Class="WpfApp1.MainWindow"
...>
<Grid>
<Button Name="button" Content="Start" Click="Button_Click"/>
<TextBox Name="textButton" />
</Grid>
</Window>
以及后面的关联代码:
public partial class MainWindow:Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
textButton.Text = "Running...";
string result = await DoIt();
textButton.Text = result;
}
private async Task<string> DoIt()
{
await Task.Delay(3000);
return "Finished...";
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
专用异步无效按钮\u单击(对象发送方,路由目标)
{
Text按钮。Text=“正在运行…”;
字符串结果=等待DoIt();
Text按钮。Text=结果;
}
私有异步任务DoIt()
{
等待任务。延迟(3000);
返回“完成…”;
}
}
单击该按钮时,“DoIt”中长期运行的“计算”将“异步”启动。当它运行时,UI将保持响应。
当DoIt返回其结果时(在本例中,虚拟延迟3秒后),“单击”事件处理程序继续
备注:
- 为了简单起见,本例使用代码隐藏。该技术也可以使用MVVM模式(异步操作从命令启动)
- “async void”是一种反模式,但用于遵守代码隐藏中自动生成的eventhandler
- 在实际应用程序中,异步“DoIt”方法可能位于后端“模型类”中
- 本例假设您只想在长时间运行的操作完成后更新UI。如果您想进行中间更新,有几个选项(遗憾的是,有点复杂)
ServiceController
是一个相当过时的类,它本身不支持async
/wait
。如果可能的话,这将是最干净的解决方案
因此,您可以使用async
/wait
和任务。运行任务。运行在后台线程上执行代码,您可以从UI使用async
/wait
来使用该后台操作。这种方法允许以自然方式传播和处理异常,并且允许自然处理返回值。为了简单起见,现在去掉文本框更新,第一步如下所示:
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var osVersion = await Task.Run(() => CheckStatus());
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus()
{
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var progress = new Progress<string>(update =>
{
TxtBoxstatus.AppendText(update);
TxtBoxstatus.AppendText(Environment.NewLine);
});
var osVersion = await Task.Run(() => CheckStatus(progress));
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus(IProgres<string> progress)
{
progress?.Report("Checking Remote Registry service status on computer : " + ComputerName);
progress?.Report("Please wait... ");
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
progress?.Report("The Remote Registry service status is currently set to : " + sc.Status.ToString());
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
progress?.Report("Starting Remote Registry service...");
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
progress?.Report("The Remote Registry status is now set to:" + sc.Status.ToString());
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
接下来,添加进度更新。这有一个内置机制-IProgress
/progress
,其工作原理如下:
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var osVersion = await Task.Run(() => CheckStatus());
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus()
{
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
private async void Button1_Click(object sender, EventArgs e)
{
try
{
var progress = new Progress<string>(update =>
{
TxtBoxstatus.AppendText(update);
TxtBoxstatus.AppendText(Environment.NewLine);
});
var osVersion = await Task.Run(() => CheckStatus(progress));
richTextBox1.AppendText("OS version is : " + osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
catch (InvalidOperationException ex)
{
richTextBox1.AppendText("Error getting registry value from" + ComputerName);
richTextBox1.AppendText(ex.ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
private string CheckStatus(IProgres<string> progress)
{
progress?.Report("Checking Remote Registry service status on computer : " + ComputerName);
progress?.Report("Please wait... ");
ServiceController sc = new ServiceController("RemoteRegistry", ComputerName);
progress?.Report("The Remote Registry service status is currently set to : " + sc.Status.ToString());
if (sc.Status == ServiceControllerStatus.Stopped)
{
// Start the service if the current status is stopped.
progress?.Report("Starting Remote Registry service...");
// Start the service, and wait until its status is "Running".
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 3));
sc.Refresh();
sc.WaitForStatus(ServiceControllerStatus.Running);
progress?.Report("The Remote Registry status is now set to:" + sc.Status.ToString());
}
var reg = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName);
var key = reg.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\");
return (key.GetValue("CurrentVersion")).ToString();
}
private async void按钮1\u单击(对象发送方,事件参数e)
{
尝试
{
变量进度=新进度(更新=>
{
TxtBoxstatus.AppendText(更新);
TxtBoxstatus.AppendText(Environment.NewLine);
});
var osVersion=wait Task.Run(()=>CheckStatus(progress));
richTextBox1.AppendText(“操作系统版本为:”+osVersion);
richTextBox1.AppendText(Environment.NewLine);
}
捕获(无效操作异常ex)
{
richTextBox1.AppendText(“从“+ComputerName”获取注册表值时出错);
richTextBox1.AppendText(例如ToString());
richTextBox1.AppendText(Environment.NewLine);
}
}
私有字符串检查状态(IProgres进度)
{
进度?.Report(“正在检查计算机上的远程注册表服务状态:“+ComputerName”);
进度?报告(“请稍候…”);
ServiceController sc=新的ServiceController(“RemoteRegistry”,ComputerName);
progress?.Report(“远程注册表服务状态当前设置为:”+sc.status.ToString());
如果(sc.Status==ServiceControllerStatus.Stopped)
{
//如果当前状态为“已停止”,则启动服务。
进度?.Report(“正在启动远程注册表服务…”);
//启动服务,并等待其状态为“正在运行”。
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running,新的时间跨度(0,0,3));
sc.Refresh();
sc.WaitForStatus(服务控制器Status.Running);
progress?.Report(“远程注册表状态现在设置为:”+sc.status.ToString());
}
var reg=RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine,ComputerName);
var key=reg.OpenSubKey(@“Software\Microsoft\Windows NT\CurrentVersion\”);
return(key.GetValue(“CurrentVersion”).ToString();
}
注意关注点的分离:唯一涉及UI对象的代码是UI事件处理程序。包含实际程序逻辑的CheckStatus
方法与UI分离-它所知道的是它可以报告进度字符串并返回字符串结果。后台工作人员应该为此工作,这就是job这些都是为你设计的。你遇到了什么问题