Я добавляю пользовательский интерфейс к некоторому коду, который я написал для мессенджера, некоторое время назад. Кажется, все идет хорошо, кроме того, когда я пытаюсь отображать новые сообщения из другого потока.Почему этот Grid/TextBlock не создается?
Программа потоков таким образом:
MainWindow
получает создан и экземпляр. КонструкторMainWindow
:public MainWindow() { InitializeComponent(); _messageContainer = (StackPanel)FindName("Messages"); _messageStatus = (StatusBarItem)FindName("MessageStatus"); _messageCountElement = (StatusBarItem)FindName("MessageCount"); _messageBox = (TextBox)FindName("MessageToSend"); _sendButton = (Button)FindName("SendMessage"); _ipAddress = GetIPAddress(); try { Client.Initialize(_ipAddress, this); _sendButton.IsEnabled = true; _messageBox.IsEnabled = true; } catch (Exception e) { DisplayMessage("Could not connect to " + _ipAddress.ToString() + ". The error given was '" + e.Message + "'.", "Server", Colors.Red); } }
отправки клиенту (
Client
класс) инициализируется с помощьюClient.Initialize
изMainWindow
конструктора.Client.Initialize
:public static void Initialize(IPEndPoint endPoint, MainWindow window) { windowInstance = window; client = new TcpClient(); client.ReceiveTimeout = 500; listenerThread = new Thread(new ParameterizedThreadStart(Receiver.Start)); listenerThread.Start((object)new StartupData(endPoint, windowInstance)); client.Connect(endPoint); }
Слушатель поток запускается из
Client.Initialize
. Метод прослушиванияStart
длинный и сложный, но работает отлично. Это сводится к вызову другого метода,ProcessMessage
для обработки того, что он получает.ProcessMessage
:public static void ProcessMessage(string response) { response = response.Trim(); MessageBox.Show(response); if (response.StartsWith("[Message]")) { MessageBox.Show("Message"); response = response.Substring(9); int openIndex = response.IndexOf("<"); int closeIndex = response.IndexOf(">"); if (openIndex < 0 || closeIndex < 0 || closeIndex < openIndex) { throw new FormatException("Could not find ID tag in message"); } int diff = closeIndex - openIndex; int id = Int32.Parse(response.Substring(openIndex + 1, diff - 1)); if (id != Client.GetClientId()) { MessageBox.Show("Them"); string message = response.Substring(closeIndex + 1); window.DisplayMessage(message, "Them", Colors.Yellow); } else { MessageBox.Show("You"); string message = response.Substring(closeIndex + 1); window.DisplayMessage(message, "You", Colors.Blue); } } else if (response.Length == 5 && response.StartsWith("[") && response.EndsWith("]")) { MessageBox.Show("Response code"); Client.HandleResponse(ResponseCodes.GetResponse(response)); } else { try { Int32.Parse(response); MessageBox.Show("ID"); Client.SetClientId(Int32.Parse(response)); return; } catch (Exception) { window.DisplayMessage(response, "Server", Colors.Red); } } }
Метод
DisplayMessage
называется.DisplayMessage
:public void DisplayMessage(string message, string name, Color nameColor) { MessageBox.Show("Called"); UpdateMessageStatus(ProcessingStatus.Processing); Grid fullMessage = new Grid(); fullMessage.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50.00) }); fullMessage.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(600.00) }); Label nameLabel = new Label { Content = string.Format("[{0}]", name), Foreground = new SolidColorBrush(nameColor) }; Grid.SetColumn(nameLabel, 0); TextBlock textLabel = new TextBlock { Text = message, TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0, 5, 0, 5) }; Grid.SetColumn(textLabel, 1); fullMessage.Children.Add(nameLabel); fullMessage.Children.Add(textLabel); UpdateMessageStatus(ProcessingStatus.Displaying); Dispatcher.BeginInvoke(new Action(delegate() { _messageContainer.Children.Add(fullMessage); })); _messageCount += 1; UpdateMessageCount(); UpdateMessageStatus(ProcessingStatus.Ready); }
Вот проблема. Когда я звоню window.DisplayMessage
из прослушивающей нитки, буквально ничего бывает. Даже не исключение, но главное, сообщение Grid не создается.
Что случилось с этим? Я добавил Dispatcher.BeginInvoke
по совету другого вопроса SO, чтобы убедиться, что ответственность за нить не является проблемой, хотя то же самое произошло до этого.
(примечание: все MessageBox
эс только для отладки Интересно, что MessageBox
в верхней части DisplayMessage
делает шоу, когда вызывается из слушающего потока.).
Вы уверены, что находитесь в потоке пользовательского интерфейса с этим вызовом BeginInvoke? Попробуйте 'Application.Current.Dispatcher.BeginInvoke' и посмотрите, дает ли это разные результаты. – Chris