2009-07-15 37 views
3

我有一个处理与外部服务通信的后台线程。每次后台线程收到一条消息时,我都想将它传递给UI线程以供进一步处理(向用户显示)。在ui线程中执行委托(使用消息泵)

目前我已经做了一个线程安全的消息队列,定期存储在Timer.Tick中并填充后台线程。但是这个解决方案是次优的。

你知道如何使用消息泵将事件从后台线程传递到UI线程吗?

+0

的WinForms?或wpf? – 2009-07-15 16:29:44

+0

winforms,但我想听两个 – 2009-07-15 17:34:39

回答

4

有几种技术。

  1. Control.Invoke()(等人)

    我发现这个的WinForms技术始终好用,但要知道,有你需要得到正确的一些微妙的规则。我试图捕获一个通用的工作实现,它能够正确处理代码段posted elsewhere on stackoverflow中的规则。

  2. SynchronizationContext

    我没有必要向太多使用这种技术,所以我真的不能说什么意义了。但是,您应该知道它存在。我相信这是确保在特定线程的上下文中调用某些东西的有效方法,即使该线程是而不是 ui线程。

  3. DispatcherObject.Dispatcher

    如果你使用WPF工作时,WPF控件一般会从DispatcherObject获得供应Dispatcher对象。这是一种比Control.Invoke()功能更丰富的同步技术,但也更复杂。请务必仔细阅读文档。

6

您可以使用Control.Invoke并使用委托。委托将在创建控件的线程上执行。

http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

+1

这是正确的方式来做到这一点。 – 2009-07-15 16:37:42

+0

只需确保不要将Delegate.Invoke()与Control.Invoke()混淆Control.Invoke()就是你想要的 – STW 2009-07-15 17:03:30

0

如果您的GUI线程被阻塞,不处理任何消息,你可以使用Application.DoEvents迫使GUI线程来处理该线程等待所有的消息。

要抽取消息的控制线程,当然你可以使用Control.BeginInvokeControl.Invoke方法,但要注意,Control.Invoke将阻止如果Control的拥有的线程当前阻止。

0

您可以使用WPF调度程序(类分派器)在WindowsBase.dll了。

0

以下是在MSMQ中使用WPF中的Dispacther对象的示例。

的背后代码:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.Messaging; 

namespace MSMQGui 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private string queueName = @".\private$\MyFunWithMSMQ"; 
     private MessageQueue queue = null; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      if (!MessageQueue.Exists(queueName)) 
       MessageQueue.Create(queueName,false); 


      queue = new MessageQueue(queueName); 
      queue.ReceiveCompleted += receiveCompleted; 

     } 

     private void btnAddMessage_Click(object sender, RoutedEventArgs e) 
     { 
      string message = txtMessage.Text; 
      txtMessage.Text = String.Empty; 

      queue.Send(message); 

      MessageBox.Show("Message :" + message + " sent"); 
     } 

     private void Populate(object sender, RoutedEventArgs e) 
     { 
      try 
      { 
       queue.BeginReceive(TimeSpan.FromSeconds(1)) ;  
      } 
      catch (MessageQueueException) 
      { 
       MessageBox.Show("No message available"); 
      } 
     } 

     private void receiveCompleted(object source, ReceiveCompletedEventArgs e) 
     { 
      try 
      { 
       var message=queue.EndReceive(e.AsyncResult); 



       Action<string> addMessage= (string msg) => { 
        ListViewItem item = new ListViewItem(); 
        item.Content = msg; 
        lsvMessages.Items.Add(item); 
       }; 

       this.Dispatcher.Invoke(addMessage, message.Body as string); 
      } 
      catch (MessageQueueException) 
      { 
       MessageBox.Show("No message available"); 
      } 
     } 
    } 
} 

的XAML:

<Window x:Class="MSMQGui.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="1*"></ColumnDefinition> 
      <ColumnDefinition Width="3*"></ColumnDefinition> 
     </Grid.ColumnDefinitions> 

     <Grid.RowDefinitions> 
      <RowDefinition Height="1*"></RowDefinition> 
      <RowDefinition Height="9*"></RowDefinition>  
      <RowDefinition Height="1*"></RowDefinition> 
     </Grid.RowDefinitions> 

     <!-- First row --> 
     <Label x:Name="lblMessage" 
       Content="Message:" 
       HorizontalAlignment="Stretch" 
       VerticalAlignment="Top" 
       HorizontalContentAlignment="Right" 
       Grid.Column="0" Grid.Row="0" 
       ></Label> 
     <StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal"> 
     <TextBox x:Name="txtMessage" Width="200" HorizontalAlignment="Left" ></TextBox> 
     <Button x:Name="btnAddMessage" Content="Add message" Margin="5,0,0,0" Click="btnAddMessage_Click"></Button> 
     </StackPanel> 

     <!-- Second row --> 
     <ListView x:Name="lsvMessages" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,5,0,0"> 
     </ListView> 

     <!-- Third row--> 
     <Button x:Name="btnPopulate" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Right" Click="Populate" Content="Get messages from queque" Margin="5,0,0,0"></Button> 

    </Grid> 
</Window>