我在wpf解决方案中有一个Primedcommand类来执行快速操作,然后在另一个线程上执行任务以防止ui线程被阻塞:
public void Execute(object parameter)
{
if (CanExecute(parameter))
{
System.Windows.Application.Current.Dispatcher.Invoke(() => { _primer(); });
Task.Factory.StartNew(() => { _execute(parameter); }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
}
和PrimedCommand构造函数:
public PrimedCommand(Action primer, Action<object> execute, Predicate<object> canExecute)
{
if (primer == null)
throw new ArgumentNullException("primer");
if (execute == null)
throw new ArgumentNullException("execute");
_primer = primer;
_execute = execute;
_canExecute = canExecute;
}
@DanPuzey要求的工人方法之一:
已执行的行动:
private static void AddChoices(ref Settings RunningSettings)
{
if (Processes.ShouldExit) return;
try
{
if (RunningSettings.Initialized)
{
if (Processes.ShouldExit) return;
if (RunningSettings.WorkingDirectory != null)
{
DirectoryInfo workingDir = new DirectoryInfo(RunningSettings.WorkingDirectory);
if (!workingDir.Exists)
{
throw new DirectoryNotFoundException("The Source Directory Didn't Exist");
}
RunningSettings.CurrentStatus.AddMoment(new Moment("Loading Customers"));
Dictionary<string, string> customerNames = new Dictionary<string, string>();
Dictionary<string, string> jobNumbers = new Dictionary<string, string>();
List<DirectoryInfo> availableFolders = new List<DirectoryInfo>();
if (Tools.IsCustomer(workingDir))
{
availableFolders.Add(workingDir);
}
else if (Tools.IsCustomerContainer(workingDir))
{
availableFolders.AddRange(workingDir.EnumerateDirectories().Where(c => Tools.IsCustomer(c)));
}
else if (Tools.IsJob(workingDir))
{
availableFolders.Add(workingDir.Parent);
}
foreach (DirectoryInfo customer in availableFolders)
{
if (Processes.ShouldExit) return;
try
{
RunningSettings.CurrentStatus.AddMoment(new Moment(String.Format(" Loading Jobs For: {0}", customer)));
if (!customerNames.ContainsKey(customer.Name))
{
customerNames.Add(customer.Name, null);
}
foreach (DirectoryInfo job in customer.GetDirectories().Where(j => Tools.IsJob(j)))
{
if (Processes.ShouldExit) return;
try
{
string tempNumber = job.Name.Substring(0, 6);
if (!jobNumbers.ContainsKey(tempNumber))
{
jobNumbers.Add(tempNumber, customer.Name);
}
}
catch (Exception except)
{
ErrorHandling.Handle(except, ref RunningSettings);
}
}
}
catch (Exception excep)
{
ErrorHandling.Handle(excep, ref RunningSettings);
}
}
int count = 0;
int index = 0;
if (customerNames != null && customerNames.Count > 0)
{
RunningSettings.ClearCustomerCollection();
count = customerNames.Count;
foreach (KeyValuePair<string, string> customer in customerNames)
{
if (Processes.ShouldExit) break;
try
{
index++;
RunningSettings.AddCustomer(customer.Key, customer.Value, (index == count));
}
catch (Exception excep)
{
ErrorHandling.Handle(excep, ref RunningSettings);
}
}
RunningSettings.SortCustomers();
}
if (Processes.ShouldExit) return;
count = 0;
index = 0;
if (jobNumbers != null && jobNumbers.Keys.Count > 0)
{
RunningSettings.ClearJobCollection();
count = jobNumbers.Count;
foreach (KeyValuePair<string, string> job in jobNumbers)
{
if (Processes.ShouldExit) break;
try
{
index++;
RunningSettings.AddJob(job.Key, job.Value, (index == count));
}
catch (Exception excep)
{
ErrorHandling.Handle(excep, ref RunningSettings);
}
}
RunningSettings.SortJobs();
}
if (Processes.ShouldExit) return;
RunningSettings.CurrentStatus.AddMoment(new Moment("Loading Customers Complete"));
}
else
{
throw new InvalidOperationException("The Working Directory Was Null");
}
}
else
{
throw new InvalidOperationException("The Settings Must Be Initialized Before Customer Folders Can Be Enumerated");
}
}
catch (Exception ex)
{
ErrorHandling.Handle(ex, ref RunningSettings);
}
}
取消行动:
public static void Cancel()
{
KeepRunning = false; // Bool watched by worker processes
}
从让我们称之为执行按钮,引物的工作是设置一个属性的值,显示用户动作是否有效。
这很好,但是当我点击取消按钮将更新该状态属性以取消然后在工人类中设置一个字段以指示操作正在取消时,UI需要大约2秒钟来响应按钮点击。我已经尝试过Task.Run和Task.Factory.StartNew以及各种重载,并且创建我自己的工作线程似乎工作得最好,但仍然不是我想要的。
我正在寻找的是你点击执行按钮,状态更新为激活(更新ui)绑定到该属性然后当单击取消按钮时状态更改为取消和任务通知工人设置适当的字段(工作线程经常检查该字段并在需要时退出)。
什么不起作用是工作线程阻止ui线程更新以显示操作正在取消的用户。(状态设置为活动后暂时无法点击取消按钮)
另外值得注意的是这个解决方案是使用mvvm,其中状态是ui与转换器绑定的枚举值。
任何问题只是让我知道。