2009-09-30 13 views
16

Adlandırılmış bir iletiden gelen iletileri okuyan bir iş parçacığım var. Engelleme amaçlı bir okumadır, bu yüzden kendi iş parçacığındadır. Bu iş parçacığı bir ileti okuduğunda, iletinin hazır olduğunu ana iş parçacığında çalışan Windows Forms ileti döngüsünü bildirmesini istiyorum. Bunu nasıl yapabilirim? Win32'de bir PostMessage yapardım, ancak bu işlev Net olarak yok gibi görünmüyor (ya da en azından onu bulamadım).Windows Forms ileti döngüsüne ileti gönderme veya gönderme

cevap

15

WinForms'da bunu Control.BeginInvoke ile yapabilirsiniz. Bir örnek: SynchronizationContext kullanımı

public class SomethingReadyNotifier 
{ 
    private readonly Control synchronizer = new Control(); 

    /// <summary> 
    /// Event raised when something is ready. The event is always raised in the 
    /// message loop of the thread where this object was created. 
    /// </summary> 
    public event EventHandler SomethingReady; 

    protected void OnSomethingReady() 
    { 
     SomethingReady?.Invoke(this, EventArgs.Empty); 
    } 

    /// <summary> 
    /// Causes the SomethingReady event to be raised on the message loop of the 
    /// thread which created this object. 
    /// </summary> 
    /// <remarks> 
    /// Can safely be called from any thread. Always returns immediately without 
    /// waiting for the event to be handled. 
    /// </remarks> 
    public void NotifySomethingReady() 
    { 
     this.synchronizer.BeginInvoke(new Action(OnSomethingReady)); 
    } 
} 

WinForms bağımlı değildir, yukarıda bir temizleyici varyantı olabilir. Ana iş parçacığınızda SynchronizationContext.Current numaralı telefonu arayın ve ardından bu başvuruyu, aşağıda gösterilen sınıfın yapıcısına iletin.

public class SomethingReadyNotifier 
{ 
    private readonly SynchronizationContext synchronizationContext; 

    /// <summary> 
    /// Create a new <see cref="SomethingReadyNotifier"/> instance. 
    /// </summary> 
    /// <param name="synchronizationContext"> 
    /// The synchronization context that will be used to raise 
    /// <see cref="SomethingReady"/> events. 
    /// </param> 
    public SomethingReadyNotifier(SynchronizationContext synchronizationContext) 
    { 
     this.synchronizationContext = synchronizationContext; 
    } 

    /// <summary> 
    /// Event raised when something is ready. The event is always raised 
    /// by posting on the synchronization context provided to the constructor. 
    /// </summary> 
    public event EventHandler SomethingReady; 

    private void OnSomethingReady() 
    { 
     SomethingReady?.Invoke(this, EventArgs.Empty); 
    } 

    /// <summary> 
    /// Causes the SomethingReady event to be raised. 
    /// </summary> 
    /// <remarks> 
    /// Can safely be called from any thread. Always returns immediately without 
    /// waiting for the event to be handled. 
    /// </remarks> 
    public void NotifySomethingReady() 
    { 
     this.synchronizationContext.Post(
       state => OnSomethingReady(), 
       state: null); 
     } 
    } 
+0

Gösterildiği gibi, OnSomethingReady() yönteminde bir yarış durumu vardır. SomethingReady olayı, null denetiminden sonra ancak olay ortaya çıkmadan önce null olarak ayarlanabilir. Bundan kaçınmak için şu tavsiyeye uyun: http: //blogs.msdn.com/brada/archive/2005/01/14/353132.aspx –

+1

@wcoenen, beni affet ama sorunu çözdüm. –

18

PostMessage (ve aynı SendMessage) direkt olarak .NET ile ilişkili değildir, böylece Win32 API işlevleri ve benzerleridir. Ancak .NET, P/Invoke çağrılarını kullanarak Win32 API ile birlikte çalışma için iyi bir desteğe sahiptir.

Görünüşe göre, Win32 programlama .NET'i yapmakta yeniyseniz, this MSDN Magazine article, konu hakkında sağlam bir giriş sağlar. C#/VB.NET adresinden bu API işlevlerinin çoğunun nasıl kullanılacağı ile ilgili ayrıntılar için

The excellent pinvoke.net website. Özellikle PostMessage için See this page.

standart beyanı şudur:

void PostMessageSafe(HandleRef hWnd, uint msg, IntPtr wParam, IntPtr lParam) 
{ 
    bool returnValue = PostMessage(hWnd, msg, wParam, lParam); 
    if(!returnValue) 
    { 
     // An error occured 
     throw new Win32Exception(Marshal.GetLastWin32Error()); 
    } 
}   
+0

PostMessage'ı kullanmak istemiyorum. Yapmak istediğimi yapmanın sade bir yolu yok mu? –

+0

Kısa cevap: Hayır. –

+0

Mike doğru. Win32 API'sini temel alan Windows ileti döngüsünü kullanıyorsunuz ve bu nedenle P/Invoke gerektiriyor. – Noldorin

4

aslında göndermek isteyen misiniz:

[DllImport("user32.dll", SetLastError = true)] 
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

Fakat sayfa gösterir gibi, düzgün Win32 hataları işlemek için bu işlevi sarmak için akıllıca olacaktır

Mesaj döngüsüne bir mesaj mı yoksa sadece Formunuzdaki bazı kontrolleri güncellemek mi istiyorsunuz, mesaj kutusu vb. mi görüntülemek istiyorsunuz? Bu eskiyse, @ Noldorin'in yanıtına bakın. Bu ikincisiyse, o zaman aramayı "okuma" iş parçacığınızdan ana kullanıcı arabirimine doğru sıralamak için Control.Invoke() yöntemini kullanmanız gerekir. Bunun nedeni, denetimlerin yalnızca oluşturuldukları iş parçacığı tarafından güncelleştirilebilmesidir.

Bu, .NET'te oldukça standart bir şeydir. , Bunu nasıl anladığınızda

(Topluluk İçeriği birinci örneğe bakın) nasıl geliştirilebileceğine ilişkin Peter Duniho's blog bakınız: Temel bilgileri almak için bu MSDN makalelere başvurun kanonik teknik üzerine.