Windows Forms: модальная форма, которая открывается / закрывается приложением, а не пользователем? - PullRequest
1 голос
/ 01 октября 2008

У меня есть то, что я считаю довольно хорошо структурированным приложением форм .NET 3.5 (модульные тесты, инъекция зависимостей, SoC, формы просто передают вход и выводят на экран и не выполняют никакой логики, ядда-ядда) Я просто пропуская знание winforms о том, как заставить этот бит работать.

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

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

partial class MySustainedDialog : Form {
    public MySustainedDialog(string msg) {
        InitializeComponent();
        lbMessage.Text = msg;
    }
    public new void Show() {
        base.ShowDialog();
    }

    public new void Hide() {
        this.Close();
    }

}

public class MyNoConnectionDialog : INoConnectionDialog {
            private FakeSustainedDialog _dialog;
    public void Show() {
        var w = new BackgroundWorker();
        w.DoWork += delegate {
            _dialog = new MySustainedDialog("Connection Lost");
            _dialog.Show();
        };
        w.RunWorkerAsync();
    }

    public void Hide() {
        _dialog.Close();
    }
}

Это не работает, поскольку _dialog.Close () является вызовом между потоками. Мне удалось найти информацию о том, как решить эту проблему, в форме Windows, но не в такой ситуации, когда вам нужно создать саму форму.

Может кто-нибудь дать мне совет, как добиться того, что я пытаюсь сделать?

РЕДАКТИРОВАТЬ: Пожалуйста, обратите внимание, что я пробовал Фоновый работник только из-за отсутствия других идей, потому что я не очень хорошо знаю, как работает многопоточность для пользовательского интерфейса, поэтому я полностью открыт для предложений. Я должен также отметить, что я не хочу закрывать форму, над которой они работают в настоящее время, я просто хочу, чтобы это появилось поверх этого. Как диалоговое окно OK / Отмена, но которое я могу открывать и закрывать программно (и мне нужно контролировать, как оно выглядит)

Ответы [ 4 ]

2 голосов
/ 01 октября 2008

Я не уверен в правильности вашего общего подхода, но чтобы конкретно ответить на ваш вопрос, попробуйте изменить функцию MySustainedDialog Hide () следующим образом:

    public new void Hide()
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke((MethodInvoker)delegate { this.Hide(); });
            return;
        }

        this.Close();
    }
1 голос
/ 01 октября 2008

Есть два подхода, которые я использовал в похожих ситуациях.

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

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

Самое простое межпотоковое решение с точки зрения кода - вызвать метод Control.Invoke из вашего BackgroundWorker.

Invoke позволяет вам «публиковать» работу в элементе управления, по сути говоря, «плз иди используйте свой собственный поток для запуска этого».

1 голос
/ 01 октября 2008

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

0 голосов
/ 01 октября 2008

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

Когда вы создаете свой таймер, вы можете назначить его Timer.SynchronizingObject, чтобы он использовал основной поток пользовательского интерфейса. И придерживаться этого?

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

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