Запустить модальное диалоговое окно на не-UI потока

Я пишу простой пользовательский интерфейс данных, используя стандартную привязку данных .Net к типизированному набору данных из SQL Server.

У меня есть кнопка перезагрузки, которая называет Fill на всех DataAdapters, чтобы получить новые данные из базы данных (в случае, если другой пользователь изменил данные).

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

Я хотел бы показать модальный "Пожалуйста, подождите" диалог в фоновом потоке (чтобы его можно было анимировать), когда поток пользовательского интерфейса подключается к базе данных.

Как я могу показать модальное диалоговое окно на не-UI потока?


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

5 ответов


вы должны сделать наоборот. Запустите длительный процесс в фоновом потоке и оставьте поток пользовательского интерфейса свободным для ответа на действия пользователя.

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


код, запущенный в событиях привязки данных, должен быть отделен от пользовательского интерфейса, вероятно, используя какой-то объект передачи данных.

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

"Правка":действительно быстрый способ исправить это-заставить события работать в своем собственном делегате, используя InvokeRequired и .Invoke. Это даст методы UI контекст. Мой коллега делает это так, как будто это выходит из стиль, и это раздражает меня до бесконечности, потому что редко бывает хорошей идеей сделать это таким образом... но если вы хотите быстрое решение, это сработает. (Я не на работе, поэтому у меня нет с собой образца; я попытаюсь что-нибудь придумать.)

Edit 2: я не уверен, что то, что вы просите, возможно. Я сделал пример приложения, которое создало модальный диалог в другом потоке, и он заканчивается тем, что он не модален. Вместо использования модального диалога можно использовать другой элемент управления или набор элементов управления для указания прогресс меняется, скорее всего, прямо на той же форме?


using( var frmDialog = new MyPleasWaitDialog() ) {
    // data loading is started after the form is shown
    frmDialog.Load += (_sender, _e) {
        // load data in separate thread
        ThreadPool.QueueWorkItem( (_state)=> {
            myAdapter.Fill( myDataSet );
            // refresh UI components in correct (UI) thread
            frmDialog.Invoke( (Action)myDataControl.Refresh );
            // close dialog
            frmDialog.Invoke( (Action)frmDialog.Close() );
        }
    }

    // shows dialog
    frmDialog.ShowDialog( this );
}

вот пример использования BackgroundWorker для загрузки данных и запуска удобной для пользователя формы, чтобы показать "загрузка записей" или подобное...

    public void Run()
    {
        bgWorkrFillDS = new BackgroundWorker();
        bgWorkrFillDS.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorkrFillDS_RunWorkerCompleted);
        bgWorkrFillDS.DoWork += new DoWorkEventHandler(bgWorkrFillDS_DoWork);
        bgWorkrFillDS.RunWorkerAsync();
    }

    void bgWorkrFillDS_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bgWrkrFillDS = (BackgroundWorker)sender as BackgroundWorker;
        if (bgWrkrFillDS != null)
        {
            // Load up the form that shows a 'Loading....'
            // Here we fill in the DS
            // someDataSetAdapter.Fill(myDataSet);
        }
    }


    void bgWorkrFillDS_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // Hide or unload the form when the work is done
    }

надеюсь, что это помогает... Заботиться, Том.


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

в качестве дополнительного бонуса, это работает много быстрее, чем раньше (вызов Fill в фоновом режиме, который работал только без сетки открытие). Кто-нибудь знает почему?