2010-03-15 2 views
2

Мне нужно написать апплет VB.Net 2008, чтобы пройти через все стационарные диски, которые ищут некоторые файлы. Если я ставлю код в ButtonClick(), пользовательский интерфейс замерзает, пока код не будет сделан:Как предотвратить зависание пользовательского интерфейса во время длительного процесса?

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
    'TODO Find way to avoid freezing UI while scanning fixed drives 

    Dim drive As DriveInfo 
    Dim filelist As Collections.ObjectModel.ReadOnlyCollection(Of String) 
    Dim filepath As String 

    For Each drive In DriveInfo.GetDrives() 
     If drive.DriveType = DriveType.Fixed Then 
      filelist = My.Computer.FileSystem.GetFiles(drive.ToString, FileIO.SearchOption.SearchAllSubDirectories, "MyFiles.*") 
      For Each filepath In filelist 
       'Do stuff 
      Next filepath 
     End If 
    Next drive 
End Sub 

Google вернулся информация о контроле BackgroundWorker: Является ли это право/способом решить эту проблему? Если нет, то какое решение вы бы порекомендовали, возможно, с очень простым примером?

FWIW, я прочитал, что Application.DoEvents() является левым с VBClassic и его следует избегать.

Спасибо.

+0

Если вы собираетесь использовать решение bg-worker, обратите внимание на исключения для кросс-потоков при доступе к элементам управления через другой поток, это может стать сложным. http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx – invert

ответ

5

BackgroundWorker - это хороший способ решить вашу проблему. Фактически в документации указано следующее:

Класс BackgroundWorker позволяет запускать операцию в отдельном выделенном потоке. Длительные операции, такие как загрузки и транзакции базы данных, могут привести к тому, что пользовательский интерфейс (UI) выглядит так, как будто он перестает отвечать на запросы во время работы. Когда вам нужен гибкий пользовательский интерфейс, и вы столкнулись с большими задержками, связанными с такими операциями, класс BackgroundWorker обеспечивает удобное решение.

+1

Спасибо всем за отзыв. Я попробую элемент BackgroundWorker и отключу кнопку перед запуском фонового потока. – Gulbahar

2

Поместите процесс в отдельную тему .... ... с использованием компонента BackgroundWorker.

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

Закончено - пользовательский интерфейс все равно будет реагировать.

+0

Хорошее предложение об отключении компонентов пользовательского интерфейса, которые могут помешать фоновой задаче. – JeffH

0

A. поднимите PROGRESS BAR ... обновите его и нажмите .REFRESH это ... Если все, что вы хотите, должно показать, что вы не мертвы.

B. DoEvents - это злые звуки. LOT как «НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ГОТО ...» pleeeeze pleeeze pleeeze бывают времена и обстоятельства, когда синтаксис любого языка может быть вредным и полезным. Зачем прыгать через миллион обручей, чтобы по существу сделать «А» выше?

< мыльница>

Если вы знаете, что что-то занимает много времени, и вы знаете, что никакие другие операции, не может иметь место, пока ваш ОЖИДАНИЯ (т.е., по существу, последовательный процесс), чем если вы НИЧЕГО например, и подтолкнуть его к «фону», тогда вы будете разбрызгивать «ITS_OK_TO_CONTINUE» булевы во всей остальной части вашего кода, просто ожидая завершения процесса файла. В чем смысл? Все, что вы сделали, усложняет ваш код ради ... хм ... «хорошее программирование»? Не в моей книге.

Кому это нужно, если DoEvents «оставлен» от ICE AGE. Его ТОЧНО правильно в МНОГИХ обстоятельствах. Например: Рамка дает вам ProgressBar.Refresh , но вы увидите, что это не совсем «работает», если вы не постобрате несколько DoEvents после него.

< /мыльница>

C. Фоновая задача - это всего лишь фон; и вы обычно используете его для работы с несерийными задачами или, по крайней мере, асинхронными задачами, которые МОГУТ ИЛИ НЕ МОГУТ обновлять передний план в какой-то момент.Но я бы утверждал, что в любое время так называемая фоновая задача HALTS на переднем плане, то она (почти) по определению --- задача FOREGROUND; независимо от того, КАК ДОЛГ.

+0

Если у вас возникли проблемы с рисованием, invalidate() и update() будут немедленно перерисовываться. DoEvents - это уродливый хак, который вызывает странные проблемы. – aehiilrs

+0

Я думаю, что большинство из вас вывели слишком много ... его проблема ПРОСТО. ОТКЛЮЧЕНИЕ элементов управления, создание делегатов, использование исходников; говорить о переполнении, о чем ОП указывала его проблема. И называть DoEvents хаком на самом деле смешно, учитывая его историю. – tobrien

+0

Скажите, что вы думаете, что делает DoEvents? – aehiilrs

2

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

  1. Создать и запустить Thread объект, себя
  2. Создать Delegate и использовать асинхронный invokation (с использованием BeginInvoke).
  3. Создайте и запустите BackgroundWorker.

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

Поскольку ваш метод не возвращает значение и не обновляет интерфейс, самым быстрым решением может быть создание делегата и использование «огонь и забыть» асинхронный invokation:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
    Call New Action(AddressOf DrivesIteration).BeginInvoke(Nothing, Nothing) 
End Sub 

Private Sub DrivesIteration() 
    Dim drive As DriveInfo 
    Dim filelist As Collections.ObjectModel.ReadOnlyCollection(Of String) 
    Dim filepath As String 

    For Each drive In DriveInfo.GetDrives() 
     If drive.DriveType = DriveType.Fixed Then 
      filelist = My.Computer.FileSystem.GetFiles(drive.ToString, FileIO.SearchOption.SearchAllSubDirectories, "MyFiles.*") 
      For Each filepath In filelist 
       DoStuff(...) 
      Next 
     End If 
    Next 
End Sub 

BTW, для Блоки ..Next больше не должны заканчиваться на «Далее (что-то)», оно устарело - VB теперь выводит (что-то) сам по себе, поэтому нет необходимости указывать его явно.

+0

Спасибо за ответ. Я предпочитаю добавлять переменную в Next для упрощения чтения. – Gulbahar

Смежные вопросы