Как обрабатывать опцию включения / выключения опции при фоновой работе с делегатом? - PullRequest
0 голосов
/ 19 февраля 2019

В случае события button_click у меня есть запрос, который займет много времени.Поэтому я запускаю его на BackgroundWorker

     private void btnGenerate_Click(object sender, EventArgs e)
        {
            btnGenerate.Enabled = false;
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += delegate (object s, DoWorkEventArgs args)
            {
                Data = DataLoader.GetData(Environment.UserName); // stored procedure execution 
                if (Data != null)
                {
                    GenerateExcel(Data);
                    GenerateSingleExcel(Data);
                } 
            };    
            worker.RunWorkerCompleted += delegate (object s, RunWorkerCompletedEventArgs args)
            {
                progressBar1.Visible = false;// ProgressBarStyle.Marquee 
                btnGenerate.Enabled = true;   
            };    
            worker.RunWorkerAsync();
}

Моя проблема в том, что мне нужно установить

btnGenerate.Enable = false;

при нажатии кнопки,и включить после выполнения.

Я пробовал внутри RunWorkerCompleted, но он показывает

'Операция с несколькими потоками недопустима: элемент управления' btnGenerate 'доступен из потока, отличного отнить, в которой он был создан. '

Любое предложение будет полезным.

1 Ответ

0 голосов
/ 19 февраля 2019

Ваша основная проблема заключается в том, что события BackgroundWorker выполняются в потоке рабочего, а не в потоке пользовательского интерфейса.Но доступ к элементам пользовательского интерфейса возможен только из потока пользовательского интерфейса.

Для его решения я предлагаю использовать async/await вместо BackgroundWorker:

// declare as async
private async void btnGenerate_Click(object sender, EventArgs e)
{
    btnGenerate.Enabled = false;
    Data = await Task.Run(() => {
                var data = DataLoader.GetData(Environment.UserName); // stored procedure execution 
                if (data != null)
                {
                    GenerateExcel(Data);
                    GenerateSingleExcel(Data);
                }
                return data; // as suggested by Vlad, don't set Data on this thread
            });    

    // this is now executed back on the UI thread
    progressBar1.Visible = false;// ProgressBarStyle.Marquee 
    btnGenerate.Enabled = true;   
}

Это было бы даже предпочтительнее, еслиDataLoader предоставил асинхронный GetDataAsync, поэтому вам не понадобится Task.Run().


Если async невозможен (по какой-либо причине), ваш обработчик RunWorkerCompleted должен использоватьInvoke или BeginInvoke:

worker.RunWorkerCompleted += OnRunWorkerCompleted;
//...
public void OnRunWorkerCompleted(object s, RunWorkerCompletedEventArgs args)
{
    if (InvokeRequired)
    {
        // not on the UI thread - use (Begin-)Invoke
        BeginInvoke(new RunWorkerCompletedEventHandler(OnRunWorkerCompleted), s, args);
        return;
    }

    // now we're on the UI thread
    progressBar1.Visible = false;// ProgressBarStyle.Marquee 
    btnGenerate.Enabled = true;   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...