2010-04-19 4 views
6

Я прочитал, что C# версия выглядит следующим образом:Как мне «DoEvents» в WPF?

Application.Current.Dispatcher.Invoke(
      DispatcherPriority.Background, 
      new Action(delegate { })); 

Однако я не могу понять, как поставить пустой делегат в VB.NET, поскольку VB.NET не отображается для поддержки анонимных методов. Идеи?

Редактировать: Возможно это?

Application.Current.Dispatcher.Invoke(
    DispatcherPriority.Background, 
    New Action(Sub() 

      End Sub)) 
+0

DoEvents? Я полагаю, что они использовали DoEvents в VB6, прежде чем люди поняли, что приложение может иметь больше, чем просто поток пользовательского интерфейса. – Will

+0

Ну, современное соглашение - использовать Thread.Sleep (1) или подобное, но это не работает, когда вам нужно временно выходить из потока, чтобы пользовательский интерфейс мог обновить себя и оставаться в середине цикла обработки в WPF. – NibblyPig

+1

@SLC: Если вы делаете свою обработку в другом потоке, вам не нужно будет сообщать пользовательскому интерфейсу об обновлении (только в общем режиме обновления). –

ответ

6

VB.NET поддерживает анонимные делегат, но только как функции одного заявления. (Анонимные анонимные функции и анонимные анонимные Sub s были добавлены в VB10 в .NET 4)

Для обеспечения контекста DoEvents был разработан, чтобы позволить однопоточной среде обновлять пользовательский интерфейс и обрабатывать другие сообщения Windows во время работы делается. Не должно быть никакой пользы для вызова DoEvents (или, как вы здесь делаете, косвенно, выполняя функцию «null» на диспетчере) из другого потока, так как поток пользовательского интерфейса должен обновляться сам по себе.

В интересах отвечая на ваш вопрос, хотя, самый простой вариант будет что-то вроде этого:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _ 
    New Action(Function() 7)) 

Но, опять же, я не могу понять, что это будет на самом деле сделать.

Если то, что вы ищете просто, как выполнить код в потоке пользовательского интерфейса (например, в Control.Invoke из форм Windows), то Dispatcher.Invoke (что вы используете) правильно, вы просто должны перевести свои встроенные анонимные методы в скрытые функции и передать их в качестве делегатов. Возможно, некоторые из них могут уйти, оставив их анонимными. Например, если все, что вы делаете обновление прогресс бар, вы могли бы сделать:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _ 
    New Action(Function() progressBar.Value = 100)) 

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

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _ 
    New Action(Function() SomeFunctionName(params))) 

Другими словами, любой из анонимных делегатов, которые в коде C#, что либо :

  • более чем один оператор
  • не возвращают значение (то есть это только один вызов метода, а не функция)

Тогда вы будете ч ave для создания функций для этих лиц и передачи делегатов этим функциям, а не сложения кода, как у вас на C#.

+0

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

+0

Вы можете изменить функцию() на Sub() и просто иметь пустой Sub(), как я предположил в своем редактировании, потому что я только что подтвердил его в коде и, похоже, работает. – NibblyPig

+3

@SLC: Это справедливо только в том случае, если то, что вы делаете, происходит * в потоке пользовательского интерфейса *. Если код выполняется в другом потоке, это необязательно. ** Если то, что вы делаете *, выполняется * в потоке пользовательского интерфейса, и он занимает достаточно много времени, чтобы требовать явного обновления пользовательского интерфейса, тогда его следует перенести в другой поток. ** –

0

Использование функции ключевого слова:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, New Action(Function() Do ... End Function)) 
+0

Проблема в том, что действие ничего не делает, так что я могу положить туда, что «ничего» «? Также функция возвращает переменную. – NibblyPig

+0

Скомпилирует ли это, если вы просто удалите точки? О какой версии VB/.NET мы говорим здесь? –

1

У вас здесь два вопроса, поэтому я собираюсь добавить два ответа. Здесь я отвечаю «как делать DoEvents в WPF».Беа Stollnitz охватывает это на her blog, а вот код в VB:

publicShared Sub WaitForPriority(priority As DispatcherPriority) 
    Dim frame As New DispatcherFrame() 
    Dim dispatcherOperation As DispatcherOperation = Dispatcher.CurrentDispatcher.BeginInvoke(priority, New DispatcherOperationCallback(ExitFrameOperation), frame) 
    Dispatcher.PushFrame(frame) 
    If dispatcherOperation.Status <> DispatcherOperationStatus.Completed Then 
     dispatcherOperation.Abort() 
    End If 
End Sub 

Private Shared Function ExitFrameOperation(obj As Object) As Object 
    (DirectCast(obj, DispatcherFrame)).[Continue] = False 
    Return Nothing 
End Function 
3

Вы можете просто вызвать этот метод, если вы хотите что-то обновляется на интерфейсе:

System.Windows.Forms.Application.DoEvents 

Мы используем его на наших приложений WPF Window и XBAP.

0

или просто использовать диспетчеру, чтобы сделать себе DoEvents() для WPF:

'The WPF equivalent of DoEvents!! 
Public Sub DoEvents() 
    Dispatcher.Invoke(New Action(Function() 
            Return Nothing 
           End Function), DispatcherPriority.ContextIdle, Nothing) 
End Sub 
Смежные вопросы