今天主要記錄的就是發送QQ表情, WPF 微信 MVVM裡寫了,後期為了發送QQ表情,需要把TextBox替換為RichTextBox,接下來就說說替換的過程。
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; } }BindableRichTextBox
做列表的方法寫在了Emoji選項列表這個博客裡,不過因為是針對微信來做,所以,還是修改了一部分。
首先,右鍵查看微信網頁版的源文件,會看到它的表情列表大概是這個樣子的代碼,從裡面獲取title和class裡的內容,做成一個XML文件
然後,去網上找QQ的表情壓縮包,這個不是難事,然後根據class進行命名,最後使用Emoji選項列表裡的方法就可以做成列表了,看下效果圖
網頁版微信,在F12下,發送一條消息,可以看到發送的報文是“文字+[表情內容]”(指QQ的表情,Emoji現在沒看到規律),因為,在轉換的時候,也就有了目標
我們在點擊發送按鈕之前,是將發送框裡的FlowDocument轉換成String發送出去的。
轉換過程是,循環FlowDocument裡面的Blocks(Paragraph都放在Blocks裡面),然後循環Paragraph裡的Inlines,判別裡面的內容是InlineUIContainer(Image)還是Run(Text)
如果是圖片的話,則從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; }FlowDocument轉String
接收消息的是,拿到的是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); } } }String轉FlowDocument
看下最終的效果圖
在把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帖子裡有,這裡就不寫了。