Как справиться с асинхронными SQL-запросами из потоков не-пользовательского интерфейса - PullRequest
1 голос
/ 25 октября 2011

Все, я успешно использовал ADO.NET, чтобы использовать асинхронные SQL-запросы, подобные примеру ниже. В показанном примере метод ExecNonQuery вызывается из потока пользовательского интерфейса. Это хорошо работает, но мне было интересно, как бы я обработал обратный вызов, если бы мне пришлось вызывать ExecNonQuery из потока, не являющегося пользовательским интерфейсом?

Примечание. Ясно, что в таком случае я бы изменил ExecNonQuery, чтобы такие вещи, как this.toolStripStatusLabel1.Text, были соответственно обработаны или удалены.

public bool ExecNonQuery(string strCmd, string strUserMsg = "")
{
    try
    {
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = conn;
        cmd.CommandText = strCmd;
        cmd.CommandTimeout = 0;
        bIsExecuting = true;
        AsyncCallback callback = new AsyncCallback(HandleCallback);
        cmd.BeginExecuteNonQuery(callback, cmd); 
        return true;
    }
    catch (Exception Ex)
    {
        bIsExecuting = false;
        this.toolStripStatusLabel1.Text = String.Format("Ready (last error: {0})", Ex.Message);
        if (conn != null)
            conn.Close();
    }
    return false;
}

private delegate void DisplayInfoDelegate(string Text);

private void HandleCallback(IAsyncResult result)
{
    try
    {
        // Retrieve the original command object, passed
        // to this procedure in the AsyncState property
        // of the IAsyncResult parameter.

        SqlCommand command = (SqlCommand)result.AsyncState;
        int rowCount = command.EndExecuteNonQuery(result);
        string rowText = " rows affected.";
        if (rowCount == 1)
            rowText = " row affected.";
        rowText = rowCount + rowText;

        // Call the procedure from the form's thread.
        DisplayInfoDelegate del = new DisplayInfoDelegate(DisplayResults);
        this.Invoke(del, rowText);
    }
    catch (Exception ex)
    {
        // Because you are now running code in a separate thread, 
        // if you do not handle the exception here, none of your other
        // code catches the exception.

        // You can create the delegate instance as you 
        // invoke it, like this:
        this.Invoke(new DisplayInfoDelegate(DisplayResults), 
            String.Format("Ready(last error: {0}", ex.Message));
    }
    finally
    {
        bIsExecuting = false;
        if (conn != null)
            conn.Close();
    }
}

private void DisplayResults(string Text)
{
    this.toolStripStatusLabel1.Text = Text;
    this.toolStripProgressBar1.Style = ProgressBarStyle.Blocks;
    this.toolStripProgressBar1.Value = 100;
}

Спасибо за ваше время.

1 Ответ

1 голос
/ 28 октября 2011

Для вашего обратного вызова не имеет значения, какой поток выполняется ExecNonQuery - HandleCallback будет по-прежнему выполняться в потоке пула потоков.

Вы уже заметили изменение, которое необходимо внести: необращаться к элементам управления пользовательского интерфейса напрямую в ExecNonQuery, если он не запущен в потоке пользовательского интерфейса.

Nick

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...