Получите информацию из пользовательского интерфейса с помощью BackgroundWorker, а затем обновите пользовательский интерфейс - PullRequest
0 голосов
/ 25 марта 2019

Я заполняю DataGridView, запустив SQL-запрос с BackgroundWorker.Мой код работает отлично, если я запускаю его непосредственно в обработчике событий кнопки, но когда я вставляю DoWork BackgroundWorker, он не обновляет пользовательский интерфейс.Мой код ниже.

DataTable tab1table = new DataTable();

public Form1()
{
    InitializeComponent();
    Instantiatesearch1Thread();
}

private void Instantiatesearch1Thread()
{
    search1Thread.WorkerReportsProgress = true;
    search1Thread.WorkerSupportsCancellation = true;
    search1Thread.ProgressChanged += search1Thread_ProgressChanged;
    search1Thread.DoWork += search1Thread_Dowrk;
    search1Thread.RunWorkerCompleted += search1Thread_RunWorkerCompleted;
}

    private void sbutton1_Click(object sender, EventArgs e)
{
    search1Thread.RunWorkerAsync();
}
void search1Thread_Dowrk(object sender, DoWorkEventArgs e)
{
    int percentprogress = 0;
    percentprogress++;
    Thread.Sleep(1000);
    // Search1 button event handler
    using (SqlConnection conn = new SqlConnection(connectionstring))
    {

        conn.Open();
        using (SqlDataAdapter cmd = new SqlDataAdapter(comboBox1SQL, conn))
        {
            if (comboBox1.Text.Contains("ID"))
            {
                long para = long.Parse(search1.Text);
                cmd.SelectCommand.Parameters.Add(new SqlParameter
                {
                    ParameterName = "@combo1Par",
                    Value = para,
                    SqlDbType = SqlDbType.BigInt
                });
            }

            else if (comboBox1.Text.Contains("Other Thing") || comboBox1.Text.Contains("Other Stuff"))
            {
                string para = search1.Text;
                cmd.SelectCommand.Parameters.Add(new SqlParameter
                {
                    ParameterName = "@combo1Par",
                    Value = "%" + para + "%",
                    SqlDbType = SqlDbType.NVarChar,
                });
            }
            // Clear datatable if it contains any information and then fill it
            // tab1datatable is a DataGridView
            if (tab1table != null)
                tab1table.Clear();
            cmd.Fill(tab1table);
            //tab1datatable.DataSource = tab1table;

        // A bunch of expensive calculations 
        }
    }
}

void search1Thread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    search1Progress.Value = e.ProgressPercentage;
}

void search1Thread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    tab1datatable.DataSource = tab1table;
    tab1datatable.Refresh();
    MessageBox.Show("All Done!");
}

Используя MessageBox, я обнаружил, что код не обращается к операторам if comboBox1.Text.Contains(), что, я думаю, имеет смысл, поскольку эта информация поступает из пользовательского интерфейса и BackgroundWorker не может напрямую получить доступ к интерфейсу.Это также объясняет, почему тогда tab1datatable и tab1table остаются нетронутыми.

Я думаю, что мне нужно где-то использовать метод Invoke, но я не уверен, как это сделать.Я взглянул на c # - Передача информации в BackgroundWorker из пользовательского интерфейса во время выполнения , но на самом деле он не отвечает на мой вопрос.Если Invoke - это то, что мне нужно, как я могу реализовать в этом коде, чтобы он мог получать информацию из пользовательского интерфейса и впоследствии обновлять ее, заполняя DataGridView?

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Вот что вам нужно сделать:

    private string search1_Text = "";
    private string comboBox1_Text = "";
    private void Instantiatesearch1Thread()
    {
        search1_Text = search1.Text;
        comboBox1_Text = comboBox1.Text;
        search1Thread.WorkerReportsProgress = true;
        search1Thread.WorkerSupportsCancellation = true;
        search1Thread.ProgressChanged += search1Thread_ProgressChanged;
        search1Thread.DoWork += search1Thread_Dowrk;
        search1Thread.RunWorkerCompleted += search1Thread_RunWorkerCompleted;
    }

Обычно вы берете копию нужных вам данных до запуска фонового рабочего.

Затемвы просто получаете доступ к полям в вашем DoWork коде:

    void search1Thread_Dowrk(object sender, DoWorkEventArgs e)
    {
        int percentprogress = 0;
        percentprogress++;
        Thread.Sleep(1000);
        // Search1 button event handler
        using (SqlConnection conn = new SqlConnection(connectionstring))
        {
            conn.Open();
            using (SqlDataAdapter cmd = new SqlDataAdapter(comboBox1SQL, conn))
            {
                if (comboBox1_Text.Contains("ID"))
                {
                    long para = long.Parse(search1_Text);
                    cmd.SelectCommand.Parameters.Add(new SqlParameter
                    {
                        ParameterName = "@combo1Par",
                        Value = para,
                        SqlDbType = SqlDbType.BigInt
                    });
                }

                else if (comboBox1_Text.Contains("Other Thing") || comboBox1_Text.Contains("Other Stuff"))
                {
                    string para = search1_Text;
                    cmd.SelectCommand.Parameters.Add(new SqlParameter
                    {
                        ParameterName = "@combo1Par",
                        Value = "%" + para + "%",
                        SqlDbType = SqlDbType.NVarChar,
                    });
                }
                // Clear datatable if it contains any information and then fill it
                // tab1datatable is a DataGridView
                if (tab1table != null)
                    tab1table.Clear();
                cmd.Fill(tab1table);
                //tab1datatable.DataSource = tab1table;

                // A bunch of expensive calculations 
            }
        }
    }
0 голосов
/ 25 марта 2019

Я не уверен, является ли это хорошим решением или нет, но это работает. Установите CheckForIllegalCrossThreadCalls в false при инициализации BackgroundWorker.

private void Instantiatesearch1Thread()
{
    // Initialize other stuff
    CheckForIllegalCrossThreadCalls = false;
}

И установите его в false, как только задача будет завершена.

private void search1Thread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Do your work,
    CheckForIllegalCrossThreadCalls = true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...