private void gridEmojiGallery_Loaded(object sender, RoutedEventArgs e) { if (isGridEmojiGalleryLoaded) { return; } var gs = from ei in EmojiGallery.EmojiDic.Values group ei by ei.category into g select new { Category = g.Key, Emojis = g }; Grid gridEmojiCategory = new Grid(); List <ScrollViewer> sv_list = new List <ScrollViewer>(); int index = 0; foreach (var g in gs) { string category = g.Category; gridEmojiCategory.ColumnDefinitions.Add(new ColumnDefinition()); gridEmojiCategory.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Auto); Image imgCategory = new Image(); imgCategory.SetValue(Grid.ColumnProperty, index); imgCategory.Height = imgCategory.Width = 25; if (true) { imgCategory.Source = new BitmapImage(new Uri(EmojiGallery.GetEmojiUri(g.Emojis.First().unicode))); } imgCategory.ToolTip = new ToolTip() { Content = g.Category }; imgCategory.MouseEnter += (_sender, _e) => { if (!sv_list.Any(_sv => _sv.Name == "svEmoji_" + g.Category)) { Grid gridEmoji = new Grid(); int row, column; column = (int)this.popupEmojiGallery.Width / 25; row = g.Emojis.Count() / column + 1; for (int i = 0; i < row; i++) { gridEmoji.RowDefinitions.Add(new RowDefinition()); } for (int i = 0; i < column; i++) { gridEmoji.ColumnDefinitions.Add(new ColumnDefinition()); } int _index = 0; foreach (var ei in g.Emojis) { Image imgEmoji = new Image(); imgEmoji.SetValue(Grid.RowProperty, (_index - _index % column) / column); imgEmoji.SetValue(Grid.ColumnProperty, _index % column); imgEmoji.Stretch = Stretch.Fill; imgEmoji.Height = imgEmoji.Width = 25; if (true) { imgEmoji.Source = new BitmapImage(new Uri(EmojiGallery.GetEmojiUri(ei.unicode))); } imgEmoji.ToolTip = new ToolTip() { Content = ei.name }; imgEmoji.MouseLeftButtonUp += (__sender, __e) => { string insertStr = ei.shortname; this.controlSetDic[currentChannel].txtMessage.SelectedText = insertStr; this.controlSetDic[currentChannel].txtMessage.SelectionLength = 0; this.controlSetDic[currentChannel].txtMessage.SelectionStart += insertStr.Length; }; gridEmoji.Children.Add(imgEmoji); _index++; } ScrollViewer _sv = new ScrollViewer(); _sv.SetValue(Grid.RowProperty, 0); _sv.Name = "svEmoji_" + g.Category; _sv.Content = gridEmoji; _sv.Visibility = Visibility.Collapsed; gridEmoji.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Auto); sv_list.Add(_sv); this.gridEmojiGallery.Children.Add(_sv); } foreach (var item in sv_list) { if (item.Name == "svEmoji_" + g.Category) { item.Visibility = Visibility.Visible; } else { item.Visibility = Visibility.Collapsed; } } }; gridEmojiCategory.Children.Add(imgCategory); index++; GC.Collect(); } ScrollViewer sv = new ScrollViewer(); sv.SetValue(Grid.RowProperty, 1); sv.Content = gridEmojiCategory; this.gridEmojiGallery.Children.Add(sv); this.isGridEmojiGalleryLoaded = true; }
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); }