2013-02-25 35 views
1

我有以下代码将文件上载到服务器并更新条上载的进度。用于上传和更新进度的Task.Run返回错误

private void UploadButton_Click(object sender, EventArgs e) 
{ 
    Cursor = Cursors.WaitCursor; 
    try 
    { 
     // get some info about the input file 
     System.IO.FileInfo fileInfo = new System.IO.FileInfo(FileTextBox.Text); 
     UploadDocument(fileInfo); 
     // show start message 
     LogText("Starting uploading " + fileInfo.Name); 
     LogText("Size : " + fileInfo.Length); 
    } 
    catch (Exception ex) 
    { 
     LogText("Exception : " + ex.Message); 
     if (ex.InnerException != null) LogText("Inner Exception : " + ex.InnerException.Message); 
    } 
    finally 
    { 
     Cursor = Cursors.Default; 
    } 
} 

private async void UploadDocument(System.IO.FileInfo fileInfo) 
{ 
    var someTask = await Task.Run<bool>(() => 
    { 
     // open input stream 
     using (System.IO.FileStream stream = new System.IO.FileStream(FileTextBox.Text, System.IO.FileMode.Open, System.IO.FileAccess.Read)) 
     { 
      using (StreamWithProgress uploadStreamWithProgress = new StreamWithProgress(stream)) 
      { 
       uploadStreamWithProgress.ProgressChanged += uploadStreamWithProgress_ProgressChanged; 

       // start service client 
       FileTransferWCF.FileTransferServiceClient client = new FileTransferWCF.FileTransferServiceClient(); 
       //FileTransferClient.FileTransferServiceClient client = new FileTransferClient.FileTransferServiceClient(); 

       // upload file 
       client.UploadFile(fileInfo.Name, fileInfo.Length, uploadStreamWithProgress); 

       LogText("Done!"); 

       // close service client 
       client.Close(); 
      } 
     } 

     return true; 
    }); 
} 

void uploadStreamWithProgress_ProgressChanged(object sender, StreamWithProgress.ProgressChangedEventArgs e) 
{ 
    if (e.Length != 0) 
     progressBar1.Value = (int)(e.BytesRead * 100/e.Length); 
} 

即时得到错误:“跨线程操作无效:控制‘progressBar1’从比它创建的线程以外的线程访问”在线:

progressBar1.Value = (int)(e.BytesRead * 100/e.Length); 

也许我做错了。我是.NET新任务库的新成员。

任何线索?

回答

0

您需要在UI线程上进行UI更新。

progressBar1.Invoke(new Action(() => 
    { progressBar1.Value = (int)(e.BytesRead * 100/e.Length); })); 

或替代地(如果你不想阻塞,直到方法返回)

progressBar1.BeginInvoke(new Action(() => 
    { progressBar1.Value = (int)(e.BytesRead * 100/e.Length); })); 

道歉语法,我没有在时刻访问VS。

+1

更妙的是,你可以使用'BeginInvoke',因为你不需要等待调用的结果。 – 2013-02-25 16:33:02

+1

^他说什么。 – FlyingStreudel 2013-02-25 16:33:56

+0

@MarekDzikiewicz所以它会像这样:progressBar1.BeingInvoke(new Action(()=> {progressBar1.Value =(int)(e.BytesRead * 100/e.Length);})); ?? – VAAA 2013-02-25 16:45:35

2

我推荐阅读我的async/await introasync编程的指导原则之一是避免async void;即使用async Task而不是async void,除非您正在编写事件处理程序。

此外,一旦您开始使用async,请尝试在任何地方使用它。它真的简化了代码。

所以,你的代码可以改变这样的(假设StreamWithProgress使用EAP惯例):

private async void UploadButton_Click(object sender, EventArgs e) 
{ 
    UploadButton.Enabled = false; 
    Cursor = Cursors.WaitCursor; 
    try 
    { 
    // get some info about the input file 
    System.IO.FileInfo fileInfo = new System.IO.FileInfo(FileTextBox.Text); 
    var task = UploadDocument(fileInfo); 

    // show start message 
    LogText("Starting uploading " + fileInfo.Name); 
    LogText("Size : " + fileInfo.Length); 

    await task; 

    LogText("Done!"); 
    } 
    catch (Exception ex) 
    { 
    LogText("Exception : " + ex.Message); 
    if (ex.InnerException != null) LogText("Inner Exception : " + ex.InnerException.Message); 
    } 
    finally 
    { 
    Cursor = Cursors.Default; 
    UploadButton.Enabled = true; 
    } 
} 

private async Task UploadDocument(System.IO.FileInfo fileInfo) 
{ 
    // open input stream 
    using (System.IO.FileStream stream = new System.IO.FileStream(FileTextBox.Text, System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.Read, 4096, true)) 
    { 
    using (StreamWithProgress uploadStreamWithProgress = new StreamWithProgress(stream)) 
    { 
     uploadStreamWithProgress.ProgressChanged += uploadStreamWithProgress_ProgressChanged; 

     // start service client 
     FileTransferWCF.FileTransferServiceClient client = new FileTransferWCF.FileTransferServiceClient(); 

     // upload file 
     await client.UploadFileAsync(fileInfo.Name, fileInfo.Length, uploadStreamWithProgress); 

     // close service client 
     client.Close(); 
    } 
    } 
} 

void uploadStreamWithProgress_ProgressChanged(object sender, StreamWithProgress.ProgressChangedEventArgs e) 
{ 
    if (e.Length != 0) 
    progressBar1.Value = (int)(e.BytesRead * 100/e.Length); 
} 
+0

在'finally'运行之前的某个时刻,你不想“等待”'UploadDocument'的任务吗? – Servy 2013-02-25 17:49:30

+0

好抓!编辑。 – 2013-02-25 17:54:10

+1

我甚至认为,在给定重构的情况下,LogText(“完成!”);'真的属于'UploadButton_Click',因此'UploadDocument'能够独立于UI(使文本框文本成为另一个参数)这将允许它完全移出UI类之外,并进入某种类的工人类。 – Servy 2013-02-25 17:56:49

相关问题