2013-02-25 62 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

相關問題