2

更新 これは、私が経験している興味深い問題です。バックグラウンド プロセスの実行中に進行状況ダイアログを表示する必要があります。通常、これは機能しますが、問題は、バックグラウンド プロセス内でパブリックな静的データを設定する必要があることです。これが私が達成しようとしているものの例です:

パブリック部分クラス MainWindow : Window
{
    public static Service バインディング。
    public static Result lr;
    public progressDialog dlg;

    プライベート無効ログイン()
    {
        文字列 sPwd = txtPwd.Password;
        文字列 sEmail = txtEmail.Text;
        バインディング = 新しいサービス ();
        lr = binding.login(sEmail, sPwd);
    }
    private void btnLogin_Click(オブジェクト送信者, RoutedEventArgs e)
    {
        BackgroundWorker ワーカー = 新しい BackgroundWorker;
        worker.DoWork += 新しい DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += 新しい RunWorkerCompletedEventHandler(worker_RunWorkerCompleted)
        worker.RunWorkerAsync();
        dlg = 新しい進行状況ダイアログ();
        dlg.Show();
        ログインする();
    }
    private void worker_DoWork(オブジェクト送信者, DoWorkEventArgs e)
    {
        e.Result = login();
    }
    private void worker_RunWorkerCompleted(オブジェクト送信者, RunWorkerCompletedEventArgs e)
    {
        this.Hid();
        Window1 newWindow = new Window1();
        newWindow.Show();
        dlg.Close();
    }

login() は void であり、実際には DoWork イベントの e.Result で使用する値を返さないため、これが機能しないことはわかっています。ただし、パラメーターを渡すログイン クラスを設定しましたが、UI スレッドにアクセスできないというエラーが引き続き表示されます。主な問題は、lr とバインディングが別のウィンドウからアクセスされるため、パブリックな静的データでなければならないことです (別のウィンドウから public static Service binding = MainWindow.binding; を設定します)。これを正確に設定する方法について頭を悩ませているだけです。

4

3 に答える 3

4

あなたはこれについて間違った方法で考えています。

バックグラウンドワーカーではなく、メインスレッドで進行状況ダイアログを表示する必要があります。

次に、BackgroundWorker.DoWork ハンドラーで実際の作業を行います。これはバックグラウンド スレッドで実行されます。

定期的に、作業の進行中にBackgroundWorker.ReportProgressを呼び出します。これにより、進行状況が UI スレッドにプッシュされます。

BW.ProgressChangedイベントをサブスクライブする必要があります。ここで、progressDialog の進行状況バーを更新します。これは、UI スレッドで自動的に行われます。

あなたの作業と ReportProgress への呼び出しは、DoWork イベント ハンドラー内の唯一のものである必要があります。

于 2009-12-11T20:12:04.617 に答える
2

バックグラウンド スレッドではなく、フォアグラウンド スレッドで TextBoxes (txtEmail および txtPwd) から読み取る必要があります。次に例を示します。

class MainWindow
{
  private string _email;
  private string _password;

  private void btnLogin_Click(...)
  {
    // running on UI thread here - can touch text boxes
    _email = txtEmail.Text;
    _password = txtPwd.Text;
    // ... set up worker ...
    worker.RunWorkerAsync();
  }

  private void login()
  {
    binding = new Service();
    // running on background thread here
    // but safe to access _email and _password they're just data, not UI controls
    lr = binding.login(_email, _password);
  }
}

編集:さらに良いことに、電子メールとパスワードをメンバー変数に格納するのではなく、引数として渡します。

  private void btnLogin_Click(...)
  {
    // running on UI thread here - can touch text boxes
    LoginInfo loginInfo = new LoginInfo(txtEmail.Text, txtPwd.Text);
    // ... set up worker ...
    worker.RunWorkerAsync(loginInfo);  // note argument
  }

  private void worker_DoWork(...)
  {
    LoginInfo loginInfo = (LoginInfo)(e.Argument);
    // now pass the LoginInfo to login() as an argument
  }

(そして _email および _password メンバーを削除します)

于 2009-12-11T20:39:50.180 に答える
1

非 UI スレッドで発生したイベントから呼び出されたイベント ハンドラーの UI 要素にアクセスするには、次のようなコードが必要です。

Action action = () => FinalUpdate();
if (Thread.CurrentThread != Dispatcher.Thread)
{
    Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, action);
}
else
{
    action();
}

可能であれば、Bill Wagner によるMore Effective C#のコピーを入手してください。彼は、マルチスレッドとバックグラウンド ワーカー スレッドに関するセクション全体を持っています。

于 2009-12-11T20:14:22.147 に答える