Ошибка при вызове, когда форма уже закрыта - PullRequest
4 голосов
/ 25 октября 2010

Я пытаюсь отобразить некоторую информацию в сетке, запрашиваемой с сервера SQL. Сбор данных может занять около 10 секунд, поэтому я не хочу блокировать поток пользовательского интерфейса.

У меня есть код:

ThreadPool.QueueUserWorkItem(DataUpdateThread, new UpdateParams(year));  

private struct UpdateParams
{
    internal string year;

    internal UpdateParams(string year)
    {
        this.year = year;
    }
}

private void DataUpdateThread(object state)
{
    DataTable dTable = new DataTable();
    try
    {
        this.Invoke((MethodInvoker)delegate
        {
            //stop data editing on the grid
            //scrolling marquee for user
            marquee.Visible = true;
            marquee.Enabled = true;
            grdMain.Visible = false;
            grdMain.DataSource = null;
        });

            UpdateParams parameters = (UpdateParams)state;            
            dTable = GetData(parameters.year);
    }
    catch (Exception ex)
    {
        this.Invoke((MethodInvoker)delegate
        {
            //log error + end user message
        });
    }
    finally
    {
        this.Invoke((MethodInvoker)delegate
        {
            grdMain.DataSource = dTable;
            grdMainLevel1.RefreshData();
            marquee.Visible = false;
            marquee.Enabled = false;
            grdMain.Visible = true;
        });
   }
}

Это работает большую часть времени, за исключением того, что закрываемая форма до завершения обновления завершится с ошибкой:

Невозможно вызвать Invoke или BeginInvoke для элемента управления, пока не будет создан дескриптор окна.

Я понимаю, что ошибка будет из-за того, что форма больше не существует, поэтому, когда раздел finally пытается вызвать метод в потоке пользовательского интерфейса, он не может.

Есть ли лучший способ сделать все это? Я думаю, что могу справиться с ошибками вызова, но это выглядит грязно, и я думаю, что, вероятно, пропустил более простой способ.

Ответы [ 3 ]

4 голосов
/ 25 октября 2010

Вы можете проверить, была ли форма закрыта, и не выполнять вызов, если форма была закрыта.if (this.IsHandleCreated) должно работать.Это, однако, может по-прежнему создавать проблемы, потому что форма может быть закрыта между проверкой и вызовом BeginInvokeЕдинственное «полное доказательство» решение заключается в том, чтобы заключить весь вызов в попытку / улов.

1 голос
/ 25 октября 2010

Invoke использует специальные WinForms SynchronizationContext за кулисами, к которым вы можете получить доступ с помощью SynchronizationContext.Current в любом месте вашего приложения.

ИСПРАВЛЕНИЕ после некоторого нажатия на Reflector : фактически Invoke идет прямым путем маршалинга через PostMessage, это BackgroundWorker, который использует SynchronizationContext за кулисами. Invoke выбросит, если у него нет дескриптора окна.

Как правило, вам нужно сохранить его в переменной, прежде чем запускать поток, например, пока вы все еще в потоке пользовательского интерфейса, и используйте Post или Send метод контекста в коде потока. Это приведет к правильному распределению содержимого без оконных ручек.

1 голос
/ 25 октября 2010

Попробуйте использовать InvokeRequired() до Invoke()

...