Mam wątek, który odczytuje wiadomości z nazwanego potoku. Jest to czytanie blokujące, dlatego znajduje się w jego własnym wątku. Kiedy ten wątek odczytuje komunikat, chcę, aby powiadomił pętlę komunikatów Windows Forms uruchomioną w głównym wątku, że wiadomość jest gotowa. Jak mogę to zrobić? W win32 zrobię PostMessage, ale ta funkcja nie istnieje w .Net (a przynajmniej nie mogłem jej znaleźć).Wysyłaj lub wysyłaj wiadomość do pętli komunikatów Windows Forms
Odpowiedz
W WinForms można to osiągnąć za pomocą Control.BeginInvoke. Przykład:
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));
}
}
Czystsze wariant powyżej której nie zależy na WinForms byłoby użyć SynchronizationContext
. Zadzwoń pod numer SynchronizationContext.Current w głównym wątku, a następnie przekaż odwołanie do konstruktora klasy pokazanej poniżej.
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);
}
}
PostMessage
(i podobnie SendMessage
) są funkcje Win32 API funkcji, a zatem nie są bezpośrednio związane z .NET. .NET ma jednak dobrą obsługę interakcji z API Win32, używając wywołań P/Invoke.
Jak się wydaje, jesteś nowy w tworzeniu programowania Win32. NET, this MSDN Magazine article zapewnia solidne wprowadzenie na ten temat.
The excellent pinvoke.net website szczegóły, jak korzystać z wielu z tych funkcji API z C#/VB.NET. See this page dla konkretnie PostMessage
.
Standardowa deklaracja jest następujący:
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
Ale gdy strona wskazuje, że jest mądry, by zakończyć tę funkcję obsługi błędów Win32 odpowiednio:
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());
}
}
Niekoniecznie chcę używać PostMessage. Czy nie ma prostego sposobu .Net robienia tego, co chcę robić? –
Krótka odpowiedź: nr –
Mike ma rację. Używasz pętli komunikatów systemu Windows, która jest oparta na interfejsie Win32 API, a zatem wymaga P/Invoke. – Noldorin
Czy faktycznie chcąc odpowiedzieć wiadomość do pętli wiadomości, czy po prostu chcesz zaktualizować niektóre formanty w formularzu, wyświetlić okno komunikatu itp.? Jeśli jest to pierwsze, odwołaj się do odpowiedzi @ Noldorina. Jeśli jest to drugie, musisz użyć metody Control.Invoke(), aby przekazać połączenie z wątku "czytania" do głównego wątku UI. Wynika to z tego, że elementy sterujące mogą być aktualizowane tylko przez wątek, w którym zostały utworzone.
Jest to dość standardowa rzecz w .NET. Odnoszą się do tych artykułów MSDN, aby uzyskać podstawy:
- Control.Invoke Method
- Control.InvokeRequired Property (patrz pierwszy przykład zawartość)
Kiedy zrozumiesz, jak to zrobić, patrz Peter Duniho's blog do jak poprawić w sprawie techniki kanonicznej.
- 1. Wysyłaj do github przez wiersz poleceń (Windows)
- 2. Wysyłaj NSArray do javascript
- 3. Wysyłaj pocztę bez MFMailComposeViewController
- 4. Wysyłaj przekierowania do określonych portów
- 5. Wysyłaj dane do określonego wątku
- 6. Wysyłaj logi heroku do s3
- 7. Wysyłaj tablicę z Flasha (AS3) do JavaScriptu
- 8. wysyłaj dynamicznie generowany plik jako wiadomość e-mail
- 9. Wysyłaj pliki przez PSSession
- 10. Wysyłaj wiadomości za pomocą whatsapi.net?
- 11. PHP - Wysyłaj ciasteczko z file_get_contents
- 12. Terminal Mac Wysyłaj e-mail z załącznikiem
- 13. Wysyłaj tablicę ze skryptem Ajax do PHP
- 14. Wysyłaj parametry do pliku lokalnego w UIWebView
- 15. Wysyłaj dodatkowe dane do siatki Telerik MVC
- 16. Wysyłaj UIImage do LocalwebServer za pomocą GCDWebServer
- 17. NSNotificationCenter obserwator nie wysyłaj powiadomień
- 18. Wysyłaj tekst bez tagów html
- 19. Wysyłaj ramkę wideo przez gniazdo
- 20. Wysyłaj grupę iMessage za pomocą applescript
- 21. Wysyłaj transmisję po powiadomieniu kliknij
- 22. Wysyłaj wiadomości e-mail w bezpieczny sposób
- 23. Wysyłaj HTML w e-mailu przez PHP?
- 24. Wysyłaj strumień zdjęć za pomocą ImageIO?
- 25. Wysyłaj wpisane obiekty za pośrednictwem tcp lub gniazd
- 26. Wysyłaj wiadomość e-mail w załączniku do pliku PDF jako strumień
- 27. ASP.net framework mvc, automatycznie wysyłaj e-mail
- 28. Wysyłaj dodatkowe dane dotyczące połączenia z gniazdem
- 29. Wysyłaj nagłówki z żądaniem AVPlayer w iOS
Jak pokazano, istnieje warunek wyścigu w metodzie OnSomethingReady(). Zdarzenie SomethingReady może zostać ustawione na wartość NULL po sprawdzeniu wartości NULL, ale przed wydaniem zdarzenia. Aby tego uniknąć, skorzystaj z porady tutaj: http: //blogs.msdn.com/brada/archive/2005/01/14/353132.aspx –
@ Wcoenen, wybacz mi, ale poszedłem naprzód i naprawiłem problem. –