1

ファイルをサーバーにアップロードし、アップロードの進行状況をバーで更新する次のコードがあります。

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 のタスク ライブラリは初めてです。

どんな手掛かり?

4

2 に答える 2

2

async/ awaitintroを読むことをお勧めします。プログラミングのガイドラインの 1 つは、async避けることasync voidです。つまり、イベント ハンドラーを作成している場合を除き、async Task代わりに使用します。async void

また、 を使い始めたらasync、あらゆる場所で使用するようにしてください。これにより、コードが大幅に簡素化されます。

したがって、コードは次のように変更できます ( EAP規則をStreamWithProgress使用すると仮定します)。

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);
}
于 2013-02-25T17:43:30.450 に答える
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 にアクセスできません。

于 2013-02-25T16:30:13.957 に答える