我正在尝试解决我的UI被阻止的问题,我不明白为什么。
public Task AddStuff(string myID, List<string> otherIDs)
{
Action doIt = () =>
{
this.theService.AddStuff(myID, otherIDs);
};
return Task.Factory.StartNew(doIt, TaskCreationOptions.LongRunning);
}
如果列表很长,则呼叫可能需要30秒,整个应用程序将无法响应(在Windows 7中显示为白色)。
是否有不同的方法可以阻止用户界面?
修改
好的,所以周围有很多代码,我将尝试保持这个相关性。我确实意识到回到原始代码,我删除了一些可能很重要的东西。我是否应该使用与TaskScheduler.Current
不同的TaskScheduler?
此外,没有任何Wait语句妨碍任何此代码,并且该服务不会与UI交互。
Task.Factory.StartNew(objState =>
{
LoadAssets(objState);
}, state, this.cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
private void LoadAssets(object objState)
{
LoadAssetsState laState = (LoadAssetsState)objState;
List<string> assetIDs = new List<string>();
for (int i = 0; i < laState.AddedMediaItems.Count; i++)
{
if (laState.CancellationToken.IsCancellationRequested)
return;
string assetId = this.SelectFilesStep.AssetService.GetAssetId(laState.AddedMediaItems[i], laState.ActiveOrder.OrderID);
assetIDs.Add(assetId);
}
if (laState.CancellationToken.IsCancellationRequested)
return;
this.ApiContext.AddAssetToProduct(laState.ActiveOrder.OrderID, laState.ActiveProduct.LineID, assetIDs, laState.Quantity, laState.CancellationToken).ContinueWith(task =>
{
if (laState.CancellationToken.IsCancellationRequested)
return;
App.ApiContext.GetOrderDetails(laState.ActiveOrder.OrderID, false, laState.CancellationToken).ContinueWith(orderDetailsTask =>
{
if (laState.CancellationToken.IsCancellationRequested)
return;
this.activeOrder = orderDetailsTask.Result;
this.StandardPrintProductsStep.Synchronize(this.activeOrder);
});
});
}
public Task AddAssetToProduct(string orderID, string lineID, List<string> assetIDs, int quantity, CancellationToken? cancellationToken = null)
{
Action doIt = () =>
{
if (cancellationToken.IsCancellationRequested())
return;
this.ordersService.AddAssetToProduct(orderID, lineID, assetIDs, quantity);
};
if (cancellationToken != null)
return Task.Factory.StartNew(doIt, cancellationToken.Value, TaskCreationOptions.LongRunning, TaskScheduler.Current);
else
return Task.Factory.StartNew(doIt, TaskCreationOptions.LongRunning);
}
修改
我在服务调用之前和之后放置了断点,它是阻止UI的服务调用,而不是任何其他行。
听起来没有理由认为这应该是阻止的,所以我想如果它很长并打多个电话,我就会打破这个列表。我只是想通过我的任务逻辑来确保我没有遗漏一些东西。
答案 0 :(得分:6)
是否有不同的方法可以阻止用户界面?
此调用本身不应阻止UI。但是,如果theService.AddStuff
与UI的SynchronizationContext进行某些同步,则可能导致该调用有效地阻止UI。
否则,问题可能发生在此功能之外。例如,如果对从此方法返回的任务调用Wait()
,则在UI线程中,UI线程将被阻止,直到完成为止。
您可能希望使用TaskScheduler.Default,而不是TaskScheduler.Current
。如果在基于UI线程的TaskScheduler上调度的Task中调用它,它将在UI线程上安排自己。
答案 1 :(得分:0)
希望我可以将格式化的代码放在评论中,但由于我没有看到如何,将此片段添加为答案。这是我用来确定任务是否在UI线程上运行的方法(因为你不希望它)并且操作完全不同(简单的thread.sleep)。
var state = new object();
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var task = Task.Factory.StartNew(
objState => { Console.WriteLine ("Current thread is {0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(30); },
state,
cancellationToken,
TaskCreationOptions.LongRunning,
TaskScheduler.Current);
task.Wait();