Search code examples
c#winformsprogress-bar

c# Unable to get Winform Progress Bar to Animate Error Cross-thread operation not valid


New to c#. I have a winform with a combobox, button and progress bar. On the button click event text is taken from the textbox and used in a sql query. While this query is running, I would like a progress bar (marquee - does not need to show % complete) to animate, when the query is complete I would like it to stop.
I have tried the below code but get the error:

'Cross-thread operation not valid: Control 'cbTest' accessed from a thread other than the thread it was created on.'.

private System.Windows.Forms.ProgressBar _progressBar;

public Test()
{
    InitializeComponent();
    _progressBar = progressBar;
}

private void Form1_Load_1(object sender, EventArgs e)
{
    _progressBar.Style = ProgressBarStyle.Marquee;
    _progressBar.MarqueeAnimationSpeed = 0;
}

public async void btn_Click(object sender, EventArgs e)
{
    await Task.Run(() => GetValues(_progressBar));
}

private void GetValues(System.Windows.Forms.ProgressBar progressBar)
{
    progressBar.Invoke(new System.Action(() =>
    {
        progressBar.MarqueeAnimationSpeed = 30;
    }));

    Sql.SqlQuery("exec Test..sp_Test " + cbTest.Text);

    progressBar.Invoke(new System.Action(() =>
    {
        progressBar.Style = ProgressBarStyle.Blocks;
        progressBar.Style = ProgressBarStyle.Marquee;
        progressBar.MarqueeAnimationSpeed = 0;
    }));
}

public static void SqlQuery(string queryString, string connectionString = "Data Source= Test; Initial Catalog = Test; Integrated Security = True")
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand(queryString, connection);
        command.CommandTimeout = 300;
        command.Connection.Open();
        command.ExecuteNonQuery();
    }
}

Solution

  • This has got absolutely zero to do with the ProgressBar. Raed the error message. It says that you are accessing cbTest - the ComboBox - on the wrong thread. You obviously know that you have to access the ProgressBar on the UI thread. Why do you think it's OK to do otherwise for the ComboBox?

    The solution would be to not access the ComboBox in that methopd at all. Change that method to accept a string as well and then get the Text from the ComboBox before creating the Task and pass that string in.

    To be honest, I would do nothing but the query in that method. Do all the pre-query UI stuff first, then create the Task to perform the query, passing in any data that is required. After the Task` completes, do the post-query UI stuff.