我开发了一个小项目(使用MVVM),其功能是将文件上传到FTP服务器。
用户可以查看上传进度:vm.Busycontent向用户显示已完成的百分比,这是我的viewmodel中绑定到我视图中UI元素的属性。
以下是用于读取文件和通过FTP上传的代码(这是Task vm.FtpUploadTask的一部分)
using (FileStream inputStream = File.OpenRead(file))
{
using (outputStream = request.GetRequestStream())
{
var buffer = new byte[1024 * 1024];
int totalReadBytesCount = 0;
int readBytesCount;
while ((readBytesCount = inputStream.Read(buffer, 0, buffer.Length)) > 0 && (!vm.Token.IsCancellationRequested))
{
vm.Token.ThrowIfCancellationRequested();
outputStream.Write(buffer, 0, readBytesCount);
totalReadBytesCount += readBytesCount;
var progress = totalReadBytesCount * 100.0 / inputStream.Length;
vm.BusyContent = ((int)progress).ToString();
}
}
}
MainWindow.xaml
我正在使用WPF扩展工具包BusyIndicator
<xctk:BusyIndicator IsBusy='{Binding IsBusy}'>
<xctk:BusyIndicator.BusyContentTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text='{Binding Path=DataContext.BusyContent,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}' />
</StackPanel>
</DataTemplate>
</xctk:BusyIndicator.BusyContentTemplate>
</xctk:BusyIndicator>
UploadToFTPCommand.cs
try
{
vm.FtpUploadTask = new Task(() => FTPUpload(file), vm.Token);
vm.FtpUploadTask.Start();
vm.FtpUploadTask.Wait(vm.Token);
vm.BusyContent = "upload done!";
}
catch (OperationCanceledException)
{
vm.BusyContent = "Canceled";
}
CancelCommand.cs
public class CancelCommand : ICommand
{
public void Execute(object parameter)
{
vm.TokenSource.Cancel();
}
}
取消功能有效,但有时vm.Busycontent等于
按下“取消”按钮时,应退出while循环,用户只能在catch(OperationCanceledException)中看到该消息。 任何想法如何解决这个问题?
注释
修改 问题仍然存在
using (FileStream inputStream = File.OpenRead(file))
{
using (outputStream = request.GetRequestStream())
{
var buffer = new byte[1024 * 1024];
int totalReadBytesCount = 0;
int readBytesCount;
while ((readBytesCount = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (vm.Token.IsCancellationRequested)
{
break;
}
outputStream.Write(buffer, 0, readBytesCount);
totalReadBytesCount += readBytesCount;
var progress = totalReadBytesCount * 100.0 / inputStream.Length;
vm.BusyContent = ((int)progress).ToString();
}
if (vm.Token.IsCancellationRequested)
{
inputStream.Close();
outputStream.Close();
vm.Token.ThrowIfCancellationRequested();
}
}
}
答案 0 :(得分:0)
您可能遇到与确切设置代码的方式有关的问题。没有经过它的每一行,很难说。但更重要的是:
按下“取消”按钮时,应退出while循环,用户只能在catch中看到该消息(OperationCanceledException)。
这显示了如何退出while
循环并抛出可以捕获的异常。请注意,测试断言TaskCanceledException
,但你正好抓住OperationCanceledException
。
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using NUnit.Framework;
namespace CancellationTests {
[TestFixture]
public class WhileCancellation {
[Test]
public void While_Loop_Is_Canceled_When_Cancel_Is_Requested() {
var inputFile = new FileInfo("somebigfile.txt");
var outputFile = new FileInfo("outputFile.txt");
var cts = new CancellationTokenSource();
cts.Cancel();
Assert.ThrowsAsync<TaskCanceledException>(() => TheWhileLoop(inputFile, outputFile, cts.Token));
}
private async Task TheWhileLoop(FileInfo inputFile, FileInfo outputFile, CancellationToken token) {
using (var inputStream = inputFile.OpenRead())
using (var outputStream = outputFile.OpenWrite()) {
var buffer = new byte[1024 * 1024];
var totalReadBytesCount = 0;
var readBytesCount = 0;
while ((readBytesCount = await inputStream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) {
await outputStream.WriteAsync(buffer, 0, readBytesCount, token);
token.ThrowIfCancellationRequested();
totalReadBytesCount += readBytesCount;
var progress = totalReadBytesCount * 100.0 / inputStream.Length;
vm.BusyContent = ((int)progress).ToString();
}
}
}
private static class vm {
public static string BusyContent { get; set; }
}
}
}
希望这能让你走上正轨。