private void connect(string channel) { channel = channel.Trim().ToLower(); if (string.IsNullOrEmpty(channel) || this.controlSetDic.ContainsKey(channel)) { return; } this.addChannelControls(channel); this.svChannelList.ScrollToEnd(); // 添加新频道自动滚动到底部。 WebSocket ws = manager.AddChannel(channel); ws.OnOpen += (sender, e) => { this.Dispatcher.Invoke(new Action(() => this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new Run(channel + " connected.\r\n\r\n") { Foreground = new SolidColorBrush(Colors.Gray) }))); }; ws.OnClose += (sender, e) => { this.Dispatcher.Invoke(new Action(() => this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new Run(channel + " disconnected. \r\n\r\n") { Foreground = new SolidColorBrush(Colors.Gray) }))); }; ws.OnError += (sender, e) => { this.Dispatcher.Invoke(new Action(() => this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new Run( string.Format("{0} connect error.\r\n {1} -> {2}\r\n{3}\r\n\r\n", channel, e.Message, e.Exception.Message, e.Exception.StackTrace) ) { Foreground = new SolidColorBrush(Colors.Gray) }))); }; ws.OnMessage += (sender, e) => { string time_short, time_long, message; DateTime dt = ClientManager.FormatUTC(manager.ParseTime(e.Data)); if ((DateTime.Now - dt).TotalDays < 7) { switch (DateTime.Now.Day - dt.Day) { case 0: time_short = dt.ToString("HH:mm"); time_long = dt.ToString("HH:mm:ss"); break; case 1: time_short = "昨天"; time_long = time_short + dt.ToString(" HH:mm:ss"); break; default: time_short = dt.DayOfWeek.ToString("D"); time_long = time_short + dt.ToString(" HH:mm:ss"); break; } } else { time_short = dt.ToString("yyyy-MM-dd"); time_long = time_short + dt.ToString(" HH:mm:ss"); } #region 处理message this.Dispatcher.BeginInvoke(new Action(() => { this.controlSetDic[channel].tbMessageRecord.Inlines.AddRange(new Inline[] { new Run(time_long) { Foreground = new SolidColorBrush(Colors.Gray), FontStyle = FontStyles.Italic }, new Run(Environment.NewLine) } ); })); message = manager.ParsePureText(e.Data); // 把新建控件操作放在this.Dispatcher.(Begin)Invoke方法里,可解决多线程的对象访问问题。 this.Dispatcher.Invoke(new Action(() => { string imageUrl; Image image; if (manager.TryParseImage(e.Data, out imageUrl)) { //message = string.Format("目前版本不支持图片浏览,请复制以下链接至浏览器地址栏:{1}{0}", imageUrl, Environment.NewLine); image = new Image(); try { image.Source = new BitmapImage(new Uri(imageUrl)); } catch (UriFormatException) { } // 如果Uri格式不正确就不加载图片源 this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new InlineUIContainer(image)); } else { MatchCollection matches = Regex.Matches(message, "\\:(?<EmojiShortName>\\w*)\\:"); if (matches.Count != 0) { int index = 0; foreach (Match match in matches) { if (index != match.Index) { this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new Run(message.Substring(index, match.Index - index))); } #region 加载emoji //#error 在这里设置表情框的大小。 Image img = new Image() { Width = 25, Height = 25, Stretch = Stretch.Fill }; string uri = EmojiGallery.GetEmojiUri(EmojiGallery.EmojiDic[match.Groups["EmojiShortName"].Value].unicode); if (true) { img.Source = new BitmapImage(new Uri(uri)); } this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new InlineUIContainer(img)); #endregion index = match.Index + match.Length; } if (index != message.Length) { this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new Run(message.Substring(index))); } } else { this.controlSetDic[channel].tbMessageRecord.Inlines.Add(new Run(message)); } } })); //record = string.Format("{0}{2}{1}{2}{2}", time_long, message, Environment.NewLine); this.Dispatcher.BeginInvoke(new Action(() => { this.controlSetDic[channel].tbMessageRecord.Inlines.AddRange(new Inline[] { new Run(Environment.NewLine), new Run(Environment.NewLine) } ); })); #endregion this.Dispatcher.BeginInvoke(new Action(() => this.controlSetDic[channel].svMessageRecord.ScrollToEnd() // 显示出新信息自动滚动到底部。 )); this.Dispatcher.BeginInvoke(new Action(() => { this.controlSetDic[channel].tbLatestMessageContent.Text = message; this.controlSetDic[channel].lblLatestMessageTime.Content = time_short; lock (this.currentChannel) { if (channel != this.currentChannel) { lock (this.controlSetDic[channel].brdrNewMessageBubble) { if (this.controlSetDic[channel].brdrNewMessageBubble.Visibility != Visibility.Visible) { this.controlSetDic[channel].brdrNewMessageBubble.Visibility = Visibility.Visible; } } lock (this.controlSetDic[channel].tbNewMessageCount) { int count = int.Parse(this.controlSetDic[channel].tbNewMessageCount.Text); this.controlSetDic[channel].tbNewMessageCount.Text = (count + 1).ToString(); } } } })); }; ws.Connect(); this.controlSetDic[channel].txtMessage.KeyDown += (sender, e) => { if (e.Key == Key.Enter) { if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) { this.Dispatcher.Invoke(new Action(() => { TextBox txtMessage = (TextBox)sender; string newline = Environment.NewLine; txtMessage.SelectedText = newline; txtMessage.SelectionLength = 0; txtMessage.SelectionStart += newline.Length; })); } else { this.sendInternal(channel); } } }; this.controlSetDic[channel].txtMessage.TextChanged += (sender, e) => { if (this.popupMessageEmpty.IsOpen) { this.popupMessageEmpty.IsOpen = false; } }; this.Closing += (sender, e) => { manager.RemoveChannel(channel); }; this.setCurrentChannel(channel); }