外部サービスとの通信を処理するバックグラウンドスレッドがあります。バックグラウンドスレッドがメッセージを受信するたびに、それをUIスレッドに渡して、さらに処理(ユーザーに表示)します。
現在、Timer.Tickに定期的にプールされ、バックグラウンドスレッドに入力されるスレッドセーフなメッセージキューを作成しました。しかし、このソリューションは最適ではありません。
メッセージポンプを使用して、バックグラウンドスレッドからUIスレッドにイベントを渡す方法を知っていますか?
外部サービスとの通信を処理するバックグラウンドスレッドがあります。バックグラウンドスレッドがメッセージを受信するたびに、それをUIスレッドに渡して、さらに処理(ユーザーに表示)します。
現在、Timer.Tickに定期的にプールされ、バックグラウンドスレッドに入力されるスレッドセーフなメッセージキューを作成しました。しかし、このソリューションは最適ではありません。
メッセージポンプを使用して、バックグラウンドスレッドからUIスレッドにイベントを渡す方法を知っていますか?
Control.Invokeを使用して、デリゲートを使用できます。デリゲートは、コントロールを作成したスレッドで実行されます。
いくつかのテクニックがあります。
Control.Invoke()
(et al)
このWinFormsの手法は一貫して使いやすいと思いますが、正しく理解するために必要な微妙なルールがいくつかあることに注意してください。私は、stackoverflowの他の場所に投稿したコードセグメントのルールを適切に処理する、一般的な実用的な実装をキャプチャしようとしました。
私はこのテクニックをあまり使う必要がなかったので、それについて意味のあることは何も言えません。ただし、それが存在することを知っておく必要があります。特定のスレッドがUIスレッドでなくても、特定のスレッドのコンテキストで何かが呼び出されるようにするための効果的な方法だと思います。
WPFを使用している場合、WPFコントロールは通常DispatcherObject
、Dispatcherオブジェクトを提供するために派生します。これは、よりも機能が豊富な同期手法ですがControl.Invoke()
、より複雑でもあります。ドキュメントを注意深くお読みください。
GUIスレッドがブロックされ、メッセージを処理しない場合はApplication.DoEvents
、GUIスレッドにそのスレッドで待機中のすべてのメッセージを処理させるために使用できます。
コントロールのスレッドにメッセージを送り込むには、確かにControl.BeginInvoke
orメソッドを使用できますが、の所有スレッドが現在ブロックしている場合はブロックされることにControl.Invoke
注意してください。Control.Invoke
Control
WindowsBase.dllでもWPFディスパッチャー(クラスディスパッチャー)を使用できます。
これは、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>