winforms - progressbar - El funcionamiento de la rosca cruzada no es válido en BackgroundWorker
backgroundworker wpf (2)
Quiero mostrar algunos datos sobre la carga del formulario en una vista de cuadrícula de datos, los datos que quiero mostrar se encuentran en un gran número de filas, cuando uso el procesador de trabajo en segundo plano me muestran el siguiente error.
Mi código:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
FTPUtility obj = new FTPUtility();
dataGridViewRequest.DataSource = obj.ListRequestFiles();
dataGridViewRequest.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewRequest.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewRequest.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewResponses.DataSource = obj.ListResponseFiles();
dataGridViewResponses.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewResponses.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewResponses.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Carga de formulario:
private void FormFTP_Load(object sender, EventArgs e)
{
try
{
//this.comboBoxRequests.SelectedIndex = 0;
backgroundWorker1.RunWorkerAsync();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Hay muchas formas diferentes de evitar que la forma se congele.
Por ejemplo, puede cargar sus datos de esta manera:
private async void Form_Load(object sender, EventArgs e)
{
//do some initializations
await LoadData();
//do some other initializations that you need to perform.
}
private async Task LoadData()
{
//Load your data here
//For example
FTPUtility obj = new FTPUtility();
dataGridViewRequest.DataSource = obj.ListRequestFiles();
}
De esta forma, al ejecutar el formulario, los comandos se ejecutan en la secuencia que usted escribió mientras que la IU responde y no enfrentará las dificultades comunes de utilizar BackgroundWorker
o hilos como las excepciones de operación de hilos cruzados.
El punto clave es usar async / await. Para obtener más información, lea Programación asincrónica con Async y Await.
Recuerde que de esta manera, cada vez que desee llamar a LoadData, debe llamarlo de esta manera:
await LoadData();
Y el método en el que escribe este código debe ser asincrónico:
private async void RefreshButton_Click(object sender, EventArgs e)
{
await LoadData();
}
EDITAR para .Net 4.0
Para .Net 4.0 puede usar Task.Run
o BackgroundWorker
. Recomiendo Task.Run
porque es más simple y más legible.
Tenga en cuenta que se lanzará Cross Thread Operation Exception cuando acceda a los elementos de la interfaz de usuario desde otra secuencia que no sea la interfaz de usuario. En estas situaciones, debe usar esto. this.Invoke(new Action(()=>{/*Access UI Here*/}));
en lugar. Y nunca dedique una tarea que consume mucho tiempo en su parte de invocación.
Enfoque de BackgroundWorker:
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
//If you put some code here for example MessageBox.Show("");
//The code will immadiately run and don''t wait for worker to complete the task.
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.LoadData();
}
public void LoadData()
{
var ftp = new FtpUtility();
var data = ftp.ListRequestFiles();
this.Invoke(new Action(() =>
{
//Setup columns and other UI stuff
//Set datasource of grid
this.dataGridView1.DataSource = data;
}));
}
- Recuerde dondequiera que haya usado
LoadData
anteriormente, ahora debería usarbackgroundWorker1.RunWorkerAsync();
en lugar. - Si desea hacer un trabajo después de que el trabajador complete la tarea, coloque su trabajo en
backgroundWorker1_RunWorkerCompleted
o enInvoke
parte deLoadData
.
Tarea. Enfoque de ejecución
private void Form1_Load(object sender, EventArgs e)
{
Task.Run(() =>
{
LoadData();
})
.ContinueWith(x =>
{
//You can put codes you want run after LoadData completed here
//If you access the UI here, you should use Invoke
});
//If you put some code here for example MessageBox.Show("");
//The code will immadiately run and don''t wait for worker to complete the task.
}
public void LoadData()
{
var ftp = new FtpUtility();
var data = ftp.ListRequestFiles();
this.Invoke(new Action(() =>
{
//Setup columns and other UI stuff
//Set datasource of grid
this.dataGridView1.DataSource = data;
}));
}
- Recuerde dondequiera que haya usado
LoadData
, ahora debe usarTask.Run(()=>{LoadData();});
en lugar. - Si desea hacer un trabajo después de que
LoadData
complete, coloque su trabajo enContinueWith
o enInvoke
parte deLoadData
.
Prueba esto.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
dataGridViewRequest.Invoke(new Action(() => {
FTPUtility obj = new FTPUtility();
dataGridViewRequest.DataSource = obj.ListRequestFiles();
dataGridViewRequest.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewRequest.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewRequest.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewResponses.DataSource = obj.ListResponseFiles();
dataGridViewResponses.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewResponses.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewResponses.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void FormFTP_Load(object sender, EventArgs e)
{
try
{
//this.comboBoxRequests.SelectedIndex = 0;
backgroundWorker1.RunWorkerAsync();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}