今天主要記錄的就是發送QQ表情, WPF 微信 MVVM裏寫了,後期爲了發送QQ表情,須要把TextBox替換爲RichTextBox,接下來就說說替換的過程。html
RichTextBox雖然支持文字,圖片,連接,可是,原生的它不支持Binding,這個對於MVVM是很不方便的,所以,須要給RichTextBox設置一個依賴屬性Document,來讓它支持綁定,這樣才能繼續下一步。正則表達式
public class BindableRichTextBox : RichTextBox { public new FlowDocument Document { get { return (FlowDocument)GetValue(DocumentProperty); } set { SetValue(DocumentProperty, value); } } // Using a DependencyProperty as the backing store for Document. This enables animation, styling, binding, etc... public static readonly DependencyProperty DocumentProperty = DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBox), new FrameworkPropertyMetadata(null,new PropertyChangedCallback(OnDucumentChanged))); private static void OnDucumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { RichTextBox rtb = (RichTextBox)d; rtb.Document = (FlowDocument)e.NewValue; } }
作列表的方法寫在了Emoji選項列表這個博客裏,不過由於是針對微信來作,因此,仍是修改了一部分。微信
首先,右鍵查看微信網頁版的源文件,會看到它的表情列表大概是這個樣子的代碼,從裏面獲取title和class裏的內容,作成一個XML文件ide
而後,去網上找QQ的表情壓縮包,這個不是難事,而後根據class進行命名,最後使用Emoji選項列表裏的方法就能夠作成列表了,看下效果圖spa
網頁版微信,在F12下,發送一條消息,能夠看到發送的報文是「文字+[表情內容]」(指QQ的表情,Emoji如今沒看到規律),由於,在轉換的時候,也就有了目標code
咱們在點擊發送按鈕以前,是將發送框裏的FlowDocument轉換成String發送出去的。htm
轉換過程是,循環FlowDocument裏面的Blocks(Paragraph都放在Blocks裏面),而後循環Paragraph裏的Inlines,判別裏面的內容是InlineUIContainer(Image)仍是Run(Text)blog
若是是圖片的話,則從Dictionary裏取得Key,放到要發送的報文裏,若是是文字的話,就直接放就能夠了遞歸
private string GetSendMessage(FlowDocument fld) { if (fld == null) { return string.Empty; } string resutStr = string.Empty; foreach (var root in fld.Blocks) { foreach (var item in ((Paragraph)root).Inlines) { //若是是Emoji則進行轉換 if (item is InlineUIContainer) { System.Windows.Controls.Image img = (System.Windows.Controls.Image)((InlineUIContainer)item).Child; resutStr += GetEmojiName(img.Source.ToString()); } //若是是文本,則直接賦值 if (item is Run) { resutStr += ((Run)item).Text; } } } return resutStr; }
接收消息的是,拿到的是String類型,可是顯示的時候要顯示成FlowDocument。圖片
由於咱們知道了消息的格式是XXXX[**]這種,所以,就選用正則表達式進行截取就能夠了。
首先,判斷字符串的第一位是否是「[」,若是是的話,則截取[]裏面的內容,轉換爲Image,而後將[**]從接收到的字符串上移除掉;
若是不是的話,則用正則表達式取得"["前面的值,做爲Text,而後,將取到的值從接收到的字符串上移除掉,整個過程進行遞歸,直到字符串的長度變爲0,跳出,將獲得的內容最後添加到FlowDocument裏
private void StrToFlDoc(string str,FlowDocument fld,Paragraph par) { //當遞歸結束之後,也就是長度爲0的時候,就跳出 if (str.Length <= 0) { fld.Blocks.Add(par); return; } //若是字符串裏不存在[時,則直接添加內容 if (!str.Contains('[')) { par.Inlines.Add(new Run(str)); str = str.Remove(0, str.Length); StrToFlDoc(str,fld, par); } else { //設置字符串長度 int strLength = str.Length; //首先判斷第一位是否是[,若是是,則證實是表情,用正則獲取表情,而後將字符串長度進行移除,遞歸 if (str[0].Equals('[')) { par.Inlines.Add(new InlineUIContainer(new System.Windows.Controls.Image { Width = 20, Height = 20, Source = ContantClass.EmojiCode[GetEmojiNameByRegex(str)] })); str = str.Remove(0, GetEmojiNameByRegex(str).Length); StrToFlDoc(str,fld, par); } else {//若是第一位不是[的話,則是字符串,直接添加進去 par.Inlines.Add(new Run(GetTextByRegex(str))); str = str.Remove(0, GetTextByRegex(str).Length); StrToFlDoc(str,fld, par); } } }
看下最終的效果圖
在把Textbox替換爲RichTextBox過程當中,遇到了很多阻礙,不像剛開始想的那麼簡單。
好比,點選表情添加到RichTextbox中時,發現有的時候光標並不在當前添加完的表情後面,而是在前面,或者是隔了一個跳躍,研究了大半天,在網上找到了解決辦法。
var container=new InlineUIContainer(new Image { Source = EmojiTabControlUC.SelectEmoji.Value, Height = 20, Width = 20 }, rtb.CaretPosition);
rtb.CaretPosition = container.ElementEnd;
獲取當前添加圖片的位置,而後將位置從新定義爲它以後。
還有,就是你們看到個人聊天框裏的RichTextBox的長度是對等的,原來用TextBox時,會根據內容的長度進行變化,而後有一個最大長度,可是,我如今始終也沒有找到如何讓長度Auto的方法,請大神們告知如何搞定。
代碼的話,繼續是GitHub,地址的話,在WPF 微信 MVVM帖子裏有,這裏就不寫了。