2015-05-03 51 views
4

我在前段時間爲一個信使編寫的代碼添加了一個UI。除了當我嘗試顯示來自不同線程的新消息時,它似乎還行。爲什麼這個Grid/TextBlock沒有被創建?

程序正是如此流量:

  1. 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); 
        } 
    } 
    
  2. 的發送方客戶端(Client類)使用Client.InitializeMainWindow構造函數被初始化。 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); 
    } 
    
  3. 監聽線程從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); 
         } 
        } 
    } 
    
  4. 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時,字面上什麼都沒有發生。即使是一個例外 - 但重要的是,信息網格不會被創建。

這是怎麼回事?我在另一個SO問題的建議中添加了Dispatcher.BeginInvoke,以確保線程所有權不是問題,儘管在此之前發生了同樣的事情。

(注:所有MessageBox ES是隻是爲了調試有趣的是,MessageBoxDisplayMessage頂部確實顯示從監聽線程調用時。)

+1

你確定你確實在調用BeginInvoke的UI線程上嗎?嘗試'Application.Current.Dispatcher.BeginInvoke',看看是否會產生不同的結果。 – Chris

回答

2

我不懷疑這是交叉的問題線程UI元素調用。由於您正在另一個線程上創建新的UI元素(fullMessage及其子項)。

如果您的window實例是WPF UserControl或WPF Window,那麼您可以使用它的同步上下文來執行跨線程封送處理。

  • 捕獲其同步上下文的MainWindow構造

    _syncContext = SynchronizationContext.Current;
  • 添加使用捕獲的情景,元帥正確的調度的方法。

     
    public void InvokeDisplayMessage(string message, string name, Color nameColor) 
    { 
        // In the already started spirit of message box debugging ;-) 
        MessageBox.Show("InvokeDisplayMessage Called"); 
        this._syncContext.Post(
         new SendOrPostCallback(x => DisplayMessage(message, name, nameColor)), 
         null); 
    } 
    
  • 最後改變所有的window.DisplayMessage調用你ProcessMessagewindow.InvokeDisplayMessage

+0

作品:) – ArtOfCode

+0

@ArtOfCode,更好的方法是可能的,我會更新我的答案,以反映這一點。 – Alex

相關問題