Графический интерфейс Windows Forms зависает при вызове OpenFileDialog.ShowDialog () - PullRequest
5 голосов
/ 16 июля 2011

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

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

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

В настоящее время мой код выглядит следующим образом:

private void bOpen_Click(object sender, EventArgs e)
{
    Func<Image> del = delegate
    {
        OpenFileDialog d = new OpenFileDialog();
        if (d.ShowDialog() == DialogResult.OK)
        {
            return Image.FromFile(d.FileName);
        }

        return null;
    };

    Invoke(del);
}

Я из мира Java, поэтому я не очень знаком стонкости программирования на C # UI.

Что-то мне здесь не хватает?

Ответы [ 5 ]

9 голосов
/ 17 июля 2011

Кажется, я решил проблему с добавлением атрибута [STAThread] к основному методу. Мне сказали сделать это, как только я запустил программу в отладчике, чего раньше не делал, потому что я регулярно запускал службу из Visual Studio и клиент из Windows.

[STAThread]
public static void Main(string[] args)
{
    GUI gui = new GUI();
    gui.ShowDialog();
}

Может кто-нибудь объяснить, что именно происходит, хотя

7 голосов
/ 10 августа 2016
openFileDialog1->ShowHelp = true;

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

7 голосов
/ 16 июля 2011

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

Отладка это сложно, вам нужен неуправляемый отладчик, так как эти расширения оболочки являются неуправляемым кодом. Вы можете быть в состоянии отличить что-либо от стека вызовов, когда входите в систему после тупика. Требуются символы отладки Windows, включите сервер символов Microsoft. Но наиболее эффективным подходом является использование утилиты SysInternals AutoRuns. Начните с отключения всех расширений оболочки, которые не были созданы Microsoft. Затем снова включите те, без которых вы не можете жить один за другим.

И, как вы узнали, эти расширения оболочки ожидают запуска в потоке STA и с треском проваливаются, когда не получают его. Поток пользовательского интерфейса программы всегда должен быть STA, также для поддержки буфера обмена и перетаскивания и различных видов элементов управления, таких как WebBrowser. Обычно всегда автоматически обрабатывается атрибутом [STAThread] в методе Main (), который помещается туда шаблоном проекта. И вызов Application.Run (), необходимый для реализации контракта STA. Тупик, когда нет.

4 голосов
/ 16 июля 2011

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

Это будет выглядеть так:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            m_Worker.DoWork += new DoWorkEventHandler(m_Worker_DoWork);
            m_Worker.ProgressChanged += new ProgressChangedEventHandler(m_Worker_ProgressChanged);
            m_Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_Worker_RunWorkerCompleted);
        }

        void m_Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Usually, used to update a progress bar
        }

        void m_Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Usually, used to add some code to notify the user that the job is done.
        }

        void m_Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            //e.Argument.ToString() contains the path to the file
            //Do what you want with the file returned.
        }        

        private void bOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog d = new OpenFileDialog();
            if (d.ShowDialog() == DialogResult.OK)
            {
                m_Worker.RunWorkerAsync(d.FileName);    
            }            
        }

        BackgroundWorker m_Worker = new BackgroundWorker();
    }

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

0 голосов
/ 27 сентября 2018

Я тоже встречал эту проблему. И я попробовал все решения здесь, и никто не может решить его. Затем я меняю целевой фреймворк с .Net Framework 4.7 на 4.6.2, проблема решена ...

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