代码之家  ›  专栏  ›  技术社区  ›  Piotr Czapla

在UI线程中执行委托(使用消息泵)

  •  3
  • Piotr Czapla  · 技术社区  · 15 年前

    我有一个处理与外部服务通信的后台线程。每次后台线程收到消息时,我都希望将其传递给UI线程进行进一步处理(显示给用户)。

    目前,我已经建立了一个线程安全的消息队列,它在timer中定期聚集,勾选并填充后台线程。但这个解是次最优的。

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

    5 回复  |  直到 15 年前
        1
  •  4
  •   Community CDub    8 年前

    有一些技巧。

    1. Control.Invoke() (等)

      我发现这种WinForms技术始终易于使用,但请注意,有一些微妙的规则需要您纠正。我试图捕获一个通用的、可正常工作的实现,它可以正确地处理代码段中的规则。 posted elsewhere on stackoverflow .

    2. SynchronizationContext

      我不需要经常使用这种技巧,所以我不能说什么有意义的。但是,您应该知道它存在。我认为这是确保在特定线程上下文中调用某些内容的有效方法,即使该线程是 UI线程。

    3. DispatcherObject.Dispatcher

      如果您使用的是WPF,则WPF控件通常从 DispatcherObject 提供调度程序对象。这是一种比 control.invoke()。 但也更复杂。务必仔细阅读文档。

        2
  •  6
  •   Kevin Doyon Zephaniah Grunschlag    15 年前

    您可以使用control.invoke和委托。委托将在创建控件的线程上执行。

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

        3
  •  0
  •   Mike J    15 年前

    如果您的GUI线程已被阻塞并且不处理任何消息,则可以使用 Application.DoEvents 强制GUI线程处理该线程上的所有等待消息。

    要将消息泵送到控件的线程,当然可以使用 Control.BeginInvoke Control.Invoke 方法,但请注意 控件调用 如果的拥有线程 Control 当前正在阻止。

        4
  •  0
  •   Nicolas Dorier    15 年前

    您也可以在windowsbase.dll中使用wpf调度程序(类调度程序)。

        5
  •  0
  •   Nikola Stjelja    14 年前

    下面是一个将WPF中的Dispatcher对象与msmq一起使用的示例。

    背后的代码:

    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>