![](/img/trans.png)
[英]Calling a PInvoke in an async doesn't return to the main thread after execution
[英]After calling an async method the process don't seem to go back to main thread in WPF app
我对 WPF 和线程都是新手,这部分是基于我没有编写的代码,所以我什至无法提出正确的问题或知道去哪里找。
我有一个带有可以停止和启动某些服务的切换按钮的应用程序。
当您启动应用程序时,服务正在运行。 然后,您可以单击按钮停止它们。 在等待服务停止(或启动)时,该按钮被禁用。 当所有服务都从一个 state 转换到另一个时,按钮上的文本会更改,并且应该启用该按钮,但它没有,文本正在更改,但该按钮未启用。 但是,如果我单击 GUI 上的任意位置,按钮就会启用。 这让我认为点击以某种方式(重新)激活了一个线程。
代码注释
在构造函数中,无论按钮是否启用,我都会参考 CanServicesExecute() 方法。 因此,当程序运行时,此方法一直被系统击中。
检查服务是否正在运行的部分由单独的线程完成,以便不阻止 GUI 的 rest,而仅禁用一个按钮。 它每 5 秒检查一次。
在这段代码中,我用简单的等待代替了实际检查服务是否已终止或停止,但我的问题仍然存在:在 Thread.Sleep 之后,正在设置 Servicesstate,并且按钮正在获取另一个文本,但 CanServicesExecute()不再被击中。 直到我单击 GUI 中的某个位置,然后它又被不断地击中。
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Contracts.Annotations;
using Contracts.BusinessObjects;
using eDeployment.Properties;
using eTray.Common;
using eTray.Server;
using eTray.Types.Server;
using Infrastructure.Commands;
using Settings = eDeployment.Properties.Settings;
namespace eDeployment.ViewModel
{
public class DeploymentViewModel : INotifyPropertyChanged
{
enum ServicesState
{
Running = 0,
Terminated = 1,
Transitioning = 2,
Unfinished = 3
}
private ServicesState IsServicesRunning { get; set; }
public DeploymentViewModel()
{
StopStartServicesCommand = new RelayCommand<object>(_ => StopStartServices(), _ => CanServicesExecute());
}
private void StopStartServices()
{
if (IsServicesRunning == ServicesState.Running)
StopServicesCommand();
else
{
StartServicesCommand();
}
}
private async void StopServicesCommand()
{
SetServiceState(ServicesState.Transitioning, Resources.TryStopServices);
//CheckServicesX(false);
CheckServicesProcessX(true);
}
private async void StartServicesCommand()
{
SetServiceState(ServicesState.Transitioning, Resources.TryStartServices);
LogWrite(Resources.TryStartServices, false);
//CheckServicesX(true);
CheckServicesProcessX(true);
}
private async void CheckServicesProcessX(bool starting)
{
await Task.Run(() => CheckServicesX(starting))
.ContinueWith(t => { }, TaskScheduler.FromCurrentSynchronizationContext());
}
private void CheckServicesX(bool starting)
{
Thread.Sleep(3000);
if (!starting)
{
SetServiceState(ServicesState.Terminated, Resources.ServicesTerminated);
LogWrite(Resources.ServicesTerminated, false);
}
else
{
SetServiceState(ServicesState.Running, Resources.ServicesRunning);
LogWrite(Resources.ServicesRunning, false);
}
}
private async void CheckServicesY(bool starting)
{
await Task.Delay(3000);
if (!starting)
{
SetServiceState(ServicesState.Terminated, Resources.ServicesTerminated);
LogWrite(Resources.ServicesTerminated, false);
}
else
{
SetServiceState(ServicesState.Running, Resources.ServicesRunning);
LogWrite(Resources.ServicesRunning, false);
}
}
private void SetServiceState(ServicesState servicestate, string message)
{
switch (servicestate)
{
case ServicesState.Running:
IsServicesRunning = ServicesState.Running;
ColorIndicator = "Green";
ServicesLabel = Resources.LabeL_StopServices;
break;
case ServicesState.Transitioning:
IsServicesRunning = ServicesState.Transitioning;
ColorIndicator = "Orange";
break;
case ServicesState.Terminated:
IsServicesRunning = ServicesState.Terminated;
ServicesLabel = Resources.LabeL_StartServices;
ColorIndicator = "Red";
break;
case ServicesState.Unfinished:
IsServicesRunning = ServicesState.Terminated;
ColorIndicator = "Orange";
break;
}
ServiceStatusText = message;
}
private bool CanServicesExecute()
{
if (IsServicesRunning == ServicesState.Transitioning)
return false;
return true;
}
}
}
您需要确保在您想要刷新绑定到CanServicesExecute
的Button
的状态时StopStartServicesCommand
。 您可以通过引发命令的CanExecuteChanged
事件来执行此操作。
如何引发事件取决于您正在使用的RelayCommand<T>
class 的实现。 它应该有一个引发事件的公共方法:
StopStartServicesCommand.RaiseCanExecuteChanged();
在CheckServicesX
中调用此选项,或者在您想要根据当前状态启用或禁用Button
时调用此选项。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.