使用非主UI线程显示表单消息

时间:2016-02-25 21:00:19

标签: c# multithreading forms websocket notifications

我有一个项目没有使用任何表单/按钮或类似的东西,连接Websocket并使用异步方法接收一些消息(在我自己创建的表单上)应该出现在右上角屏幕。

但是如果websocket没有说它必须停止,则此消息可能会在屏幕上不时出现(2或3分钟)。这条消息可以很大,为了让它看起来更好,我让我的消息以多种形式出现。

它会给人留下一个通知。所以我的类连接websocket并接收消息异步,使用作为控制器的线程调用另一个类。控制器的目的是不时地,在各种新的form()通知中显示该消息,并且如果websocket没有返回任何消息,显然不会这样做。

但是当我调用form.show时程序停止工作。 我已经查看了stackoverflow,但我发现的想法似乎没有用。

有人说我应该使用invoke,但它一直在说错误 “在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke”,试图像这样解决:C# calling form.show() from another thread但它不起作用。

有人说我应该使用.showDialog而不是.show,但它看起来并不好,因为它等待窗口关闭以终止方法,正如我所说我需要打开多个通知在同一时间。

有些人说表格是以.show打开的,但它在很短的时间内是开放的。但我无法注意到是否是这种情况,即使它是我无法解决它。好吧,重要的是我被困住了,我不知道该怎么做。

使用代码编辑:

//Main
Application.Run(new SocketService());

//SocketService class
        public SocketService()
        {
            alerta = null;

            while (true)
            {
                try
                {
                    //Console.WriteLine("Nome do Usúario:" + Environment.UserName);
                    Thread.Sleep(2000);
                    Connect("ws://192.168.120.38:9091").Wait();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        public static async Task Connect(string uri)
        {
            ClientWebSocket webSocket = null;

            try
            {
                webSocket = new ClientWebSocket();
                await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
                await Login(webSocket);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (webSocket != null)
                    webSocket.Dispose();

                lock (consoleLock)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("WebSocket closed.");
                    Console.ResetColor();
                }
            }
        }

        private static async Task Login(ClientWebSocket webSocket)
        {
            ArraySegment<Byte> buffer = new ArraySegment<byte>(encoder.GetBytes(        "{\"event\":\"loginBrowser\",\"data\":{\"login\":\"000000003077\",\"data\":\"1\"}}"));
            await webSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);

            if (webSocket.State == WebSocketState.Open)
            {
                if (ShowMessage.created != true)
                {
                    var dummy = new Control(); // to initialize SynchronizationContext
                    _sync = SynchronizationContext.Current;
                    new Thread(ThreadProc).Start();
                }

                await Receive(webSocket);               
            }

        }

        private static async Task Receive(ClientWebSocket webSocket)
        {
            while (webSocket.State == WebSocketState.Open)
            {
                ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[256]);
                var result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);

                if (result.MessageType == WebSocketMessageType.Close)
                {
                    await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,        CancellationToken.None);
                }
                else
                {
                    if (result.EndOfMessage)
                    {
                        message += encoder.GetString(buffer.ToArray());
                        SendMessage(message);
                    }
                    else
                    {
                        message += encoder.GetString(buffer.ToArray());
                    }
                }
            }
        }

        public static void ShowFormFromAnotherThread(string text)
        {
            _sync.Post(SendOrPostCallback, text);
        }

        private static void SendOrPostCallback(object state)
        {
            var form = new Notification();
            form.Text = (string)state;
            form.Show();
        }

        private static void ThreadProc()
        {
            while (true)
            {
                Thread.Sleep(2000); // wait imitation
                ShowFormFromAnotherThread("HI");
            }
        }

         /*Notification is my form and depending on where I put this part:
         var dummy = new Control(); // to initialize SynchronizationContext
        _sync = SynchronizationContext.Current;
        new Thread(ThreadProc).Start();

或者我没有调用登录或者没有输入receive()方法或最好的情况它接收信息             调用threadProc和ShowFormFromAnotherThread,但不输入SednOrPostCallBack * /

3 个答案:

答案 0 :(得分:1)

using System.Threading;
using System.Windows.Forms;

namespace ConsoleThreadSync
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Application.Run(new App());
        }
    }

    public class App : ApplicationContext
    {
        private readonly SynchronizationContext _sync;

        public App()
        {
            var dummy = new Control(); // to initialize SynchronizationContext
            _sync = SynchronizationContext.Current;
            new Thread(ThreadProc).Start();
        }

        public void ShowFormFromAnotherThread(string text)
        {
            _sync.Post(SendOrPostCallback, text);
        }

        private void SendOrPostCallback(object state)
        {
            var form = new Form1();
            form.Text = (string)state;
            form.Show();
        }

        private void ThreadProc()
        {
            while (true)
            {
                Thread.Sleep(2000); // wait imitation
                ShowFormFromAnotherThread("HI");
            }
        }
    }
}

答案 1 :(得分:0)

试着这样称呼:

var dummy = new Control(); // to initialize SynchronizationContext
_sync = SynchronizationContext.Current;

来自异步方法的构造函数SocketService()和而不是。这是一个初始化代码,它必须从主线程调用

答案 2 :(得分:0)

好的,在阅读了一点之后,那种解决方案就是这个,但唯一的方法是使用 来自notifician的显示是使用Application.DoEvents,并且我已经从我已查看过的消息来源发出警告 不应该使用此方法,除非是唯一的选项,因为它可能会导致线程和其他东西出现一些问题。 因此,除非有人能给我提供另外的提示或线索,我有两个选择或使用此方法并尝试修复其他一些错误 它可以导致或使用.showDialog因为不知道为什么它没有任何其他问题,但使用.showDialog我已经 使用我创建并显示通知的另一个线程,因为如果我不这样做,循环将在每次迭代时停止 为了等待.showDialog被关闭。因为它不是一个问题,我想避免使用大量的线程,因为它可能导致 他们之间同步的另一个问题是:

namespace ReiDoCSharp
{
    class ShowMessage
    {
        private static RootObject alerta;
        public static bool created;
        private static int startPosition;

        public static void setStartPosition(int start)
        {
            if (start < startPosition)
            {
                startPosition = start;
            }
        }

        public RootObject getAlerta()
        {
            return ShowMessage.alerta;
        }

        public void setAlerta(RootObject root)
        {
            ShowMessage.alerta = root;
        }

        private static void DoWork()
        {
            while (true)
            {
                if (created != true)
                {
                    created = true;
                }

                if (alerta != null)
                {
                    string mensagem = "";

                    if ((alerta.data.Informacoes[1] != "") && (alerta.data.Informacoes[1] != null))
                    {
                        mensagem += alerta.data.Informacoes[1];
                    }

                    if ((alerta.data.Informacoes[0] != "") && (alerta.data.Informacoes[0] != null))
                    {
                        mensagem += alerta.data.Informacoes[0];
                    }

                    if (mensagem != "")
                    {
                        startPosition = 5;


                        string[] messages = mensagem.Split(new[] { "<br><br>" }, StringSplitOptions.None);
                        foreach (string message in messages)
                        {

                            Notification popup = new Notification();
                            popup.label1.Text = message;
                            popup.TopMost = true;
                            popup.Show();
                            Application.DoEvents();
                            /*Solution with the ShowDialog would be:
                                Task.Run(() => showNotification(message));
                            */
                        }
                    }
                }

                Thread.Sleep(5000);
            }
        }

        //Then I won't need to use Application.DoEvents, but would have to create more threads
        private static Task showNotification(string message)
        {
            Notification popup = new Notification();
            popup.label1.Text = message;
            popup.TopMost = true;
            popup.ShowDialog();
        }

        public static Task createPopupsAsync()
        {
            Task.Run(() => DoWork());
        }
    }

}

namespace ReiDoCSharp
{
    class SocketService
    {
        private static object consoleLock = new object();
        private const bool verbose = true;
        private static readonly TimeSpan delay = TimeSpan.FromMilliseconds(3000);
        private static UTF8Encoding encoder = new UTF8Encoding();
        private static string message;
        private static RootObject alerta;

        public SocketService()
        {
            Begin();
        }

        public static void Begin()
        {
            alerta = null;

            while (true)
            {
                try
                {
                    Thread.Sleep(2000);
                    Connect("ws://192.168.120.38:9091").Wait();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        public static async Task Connect(string uri)
        {
            ClientWebSocket webSocket = null;

            try
            {
                webSocket = new ClientWebSocket();
                await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
                await Login(webSocket);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (webSocket != null)
                    webSocket.Dispose();

                lock (consoleLock)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("WebSocket closed.");
                    Console.ResetColor();
                }
            }
        }

        private static async Task Login(ClientWebSocket webSocket)
        {
            ArraySegment<Byte> buffer = new ArraySegment<byte>(encoder.GetBytes("{\"event\":\"loginBrowser\",\"data\":{\"OPERADOR\":\"000000003077\",\"NRORG\":\"1\"}}"));
            await webSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);

            if (webSocket.State == WebSocketState.Open)
            {
                Task.Factory.StartNew(() => ShowMessage.createPopupsAsync());
                await Receive(webSocket);
            }
        }

        private static async Task Receive(ClientWebSocket webSocket)
        {
            while (webSocket.State == WebSocketState.Open)
            {
                ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[256]);
                var result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);

                if (result.MessageType == WebSocketMessageType.Close)
                {
                    await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                }
                else
                {
                    if (result.EndOfMessage)
                    {
                        message += encoder.GetString(buffer.ToArray());
                        SendMessage(message);
                    }
                    else
                    {
                        message += encoder.GetString(buffer.ToArray());
                    }
                }
            }
        }

        private static void LogStatus(bool receiving, byte[] buffer, int length, string assunto)
        {
            lock (consoleLock)
            {
                Console.ForegroundColor = receiving ? ConsoleColor.Green : ConsoleColor.Yellow;

                if (verbose)
                {
                    Console.WriteLine(encoder.GetString(buffer) + "  " + assunto);
                }

                Console.ResetColor();
            }
        }

        private static void SendMessage(string message)
        {
            message = message.Replace("event", "evento");
            message = message.Replace("\0", "");

            JavaScriptSerializer js = new JavaScriptSerializer();
            RootObject mess = js.Deserialize<RootObject>(message);

            if (mess.data.Informacoes[1] != "")
            {
                mess.data.Informacoes[1] += "<br>";
            }

            if (alerta == null)
            {
                alerta = mess;
            }
            else
            {
                if ((mess.data.Quantidade[0] != 0) && (mess.data.Quantidade == null))
                {
                    if ((mess.data.Quantidade[0] == -1) && (mess.data.Informacoes[0] == ""))
                    {
                        alerta = null;
                    }
                    else
                    {
                        alerta = mess;
                    }
                }
                else if (mess.data.Quantidade[0] == 0)
                {
                    alerta = null;
                }

                if ((mess.data.Quantidade[1] != 0) && (mess.data.Informacoes[1] != ""))
                {
                    alerta = mess;
                }
            }

            new ShowMessage().setAlerta(alerta);
            message = "";
        }

    }
}