3

カレンダーとデータグリッドを含むウィンドウがあります。
ユーザーがカレンダーで新しい日付を選択すると、その日に行われた呼び出しについてデータベースにクエリを実行したいと考えています。

public HistoryDialog()
{
    InitializeComponent();

    worker = new BackgroundWorker();
    worker.WorkerSupportsCancellation = true;
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

    HistoryGrid.SelectionChanged += new SelectionChangedEventHandler(HistoryGrid_SelectionChanged);
}

void calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
    startDate = calendar.SelectedDates.OrderBy(x => x.Date).FirstOrDefault();
    endDate = calendar.SelectedDates.OrderByDescending(x => x.Date).FirstOrDefault();

    if (endDate != startDate)
        SelectedDateTextBlock.Text = String.Format("{0:d MMMM}", startDate) + " - " + String.Format("{0:d MMMM}", endDate);
    else
        SelectedDateTextBlock.Text = String.Format("{0:d MMMM}", startDate);

    SearchInDatabase();
}

private void SearchInDatabase()
{
    if (worker.IsBusy)
        worker.CancelAsync();

    worker.RunWorkerAsync();
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    if ((worker.CancellationPending == true))
    {
        e.Cancel = true;
        return;
    }

    var CallLog = ct.GetCalllogs(startDate, endDate, userID);   // Database query
    e.Result = CallLog;
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    IList CallLog = e.Result as IList;

    foreach (CalllogInfo callInfo in CallLog)
    {
        chvm.CallHistoryList.Add(callInfo);
    }
}

しかし、バックグラウンドワーカーがまだ実行されている間にユーザーが新しい日付を選択すると、プログラムがクラッシュします。

実行中のバックグラウンド ワーカーを停止し、新しいワーカーを開始するにはどうすればよいですか?

4

4 に答える 4

4

WorkerSupportsCancellationプロパティが true に設定されていることがわかります。

これは実際に BackgroundWorker をキャンセルするのではなく、単にCancelAsync()メソッドを呼び出すことを許可します。

あなたがする必要があるのは、メソッド処理で定期的にチェックして、CancellationPendingプロパティからのキャンセルが保留されていないことを確認することです。true であることがわかったときにこのプロパティをチェックすると、イベント引数の Cancel プロパティを true に設定できます。これは、RunWorkerCompletedイベントで利用できるようになります。この時点で (RunWorkerCompletedイベント ハンドラーで)、 を再起動できますBackgroundWorker

キャンセルをサポートし、キャンセル要求に応答する非常に基本的なバックグラウンド ワーカーを使用した例を次に示します。

public MainWindow()
{
    InitializeComponent();
    this.DataContext = dataModel;

    worker = new BackgroundWorker();
    worker.WorkerSupportsCancellation = true;
    worker.DoWork += (o, e) =>
    {
        //do a long running task
        for (int i = 0; i < 10; i++)
        {
            System.Threading.Thread.Sleep(500);
            if (worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
        }

    };
    worker.RunWorkerCompleted += (o, e) =>
    {
        if (e != null && e.Cancelled)
        {
            startTheWorker();
            return;
        }
        //TODO: I AM DONE!
    };
}

BackgroundWorker worker;

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (worker != null && worker.IsBusy)
        worker.CancelAsync();
    else if(worker != null && !worker.CancellationPending)
        startTheWorker();
}

void startTheWorker()
{
    if (worker == null)
        throw new Exception("How come this is null?");
    worker.RunWorkerAsync();
}

ご覧のとおり、実際にワーカーをキャンセルするすべての作業を行う必要があります。お役に立てれば。

于 2013-11-13T09:26:58.200 に答える
0

あなたの問題はキャンセルから来ています。コードにいる場合ct.GetCalllogsはブロックされ、キャンセルはサポートされていません。バックグラウンドワーカーct.GetCalllogsがキャンセル状態でないことを確認してから、新しい値でやり直す必要があります。

これは、バックグラウンドワーカーを正しく停止する方法の応答の要素です

于 2013-11-13T09:25:34.800 に答える