c # BeginInvoke Проблема - PullRequest
       9

c # BeginInvoke Проблема

1 голос
/ 02 августа 2010

У меня есть программа, которая делает несколько здоровенных вызовов в базу данных, а затем обновляет пользовательский интерфейс.Это вызывает проблемы, потому что в большинстве случаев это означает, что пользовательский интерфейс не отвечает.Поэтому я решил, что хочу поместить вызовы функций, которые получают доступ к базе данных и обновлять пользовательский интерфейс, в отдельном потоке, поэтому теперь у меня есть что-то вроде этого:в пользовательский интерфейс.Я где-то читал, что если код, который нужно запустить в отдельном потоке, необходим для обновления пользовательского интерфейса, то именно так и должен быть сделан вызов - это правильно?Я что-то не так делаю?

Ответы [ 4 ]

3 голосов
/ 02 августа 2010

Возможно, вам лучше будет использовать BackgroundWorker, встроенный в .NET Framework.

    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    bw.WorkerReportsProgress = true;

    void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // update UI with status
        label1.Text = (string)e.UserState
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
         //Check for cancel
         if(e.Cancelled)
         { 
             //Handle the cancellation.
         {

         //Check for error
         if(e.Error)
         {
             //Handle the error.

         }    

        // Update UI that data retrieval is complete
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        // Get data
        //foreach to process data
        //Report progress

        bw.ReportProgress(n, message);

    }

Ниже приведена ссылка на статью MSDN о том, как использовать BackgroundWorker для получения дополнительной информации.Спасибо Хенку Холтерману за предложение включить это:

http://msdn.microsoft.com/en-us/library/cc221403%28VS.95%29.aspx

1 голос
/ 02 августа 2010

BeginInvoke и Invoke означает запуск кода в потоке пользовательского интерфейса.В этом случае, если вы звоните CallGetDBValues() из потока пользовательского интерфейса, вы ничего не получите.

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

A BackgroundWorker, вероятно, будет лучшим решением (см. ответ Robaticus), но вот версия фонового потока.

private delegate void CallAsyncDelegate();

private void button_Click( object sender, EventArgs e )
{
    Thread thread = new Thread( GetDBValues );
    thread.IsBackground = true;
    thread.Start();
}

private void GetDBValues()
{
    foreach( ... )
    {
        Invoke( new CallAsyncDelegate( UpdateUI ) );
    }
}

private void UpdateUI()
{
    /* Update the user interface */
}
1 голос
/ 02 августа 2010

В «// Обновление пользовательского интерфейса здесь» обязательно используйте Control.Invoke, чтобы фактически выполнить работу - обязательно, чтобы пользовательский интерфейс только «касался» UI-потока, и это происходит только при использовании Control.Invoke.

0 голосов
/ 02 августа 2010

Я не уверен в синтаксисе ... но синтаксис, с которым я более знаком, выглядит примерно так:

public delegate object myDelegate(object myParam);

Public class MyClass
{
    public static void Main()
    {
        myDelegate d = new myDelegate(myMethod);
        d.BeginInvoke ( new object() );
    }

    static void myMethod(object myParam)
    {
        // do some work!!
        return new object);
    }
}
...