請來圍觀:WPF開發的微信客戶端!!!

本文經原作者授權以原創方式二次分享,歡迎轉載、分享。

原文作者:眾尋

原文鏈接:https://www.cnblogs.com/ZXdeveloper/p/6058206.html


公司的同事離職了,接下來的日子可能會忙碌,能完善DEMO的時間也會少了,因此,把做的簡易DEMO整體先記錄一下,等后續不斷的完善。

參考兩位大神的日志:WEB版微信協議部分功能分析[1]、【完全開源】微信客戶端.NET版[2]

尤其是周見智[3]大神的DEMO,因為好多和微信的服務端交互,都借鑒了大神的源碼,幫助巨大,可以說我相當于做了一個翻版,只是用WPF開發的而已,外觀上不同,但是實際交互上是差不多的。

微信分為兩個部分,一個是登錄,一個是主體,基于此,WPF也主要是這兩個窗體來實現。

一、登錄模塊

1、登錄部分分為二維碼和獲取用戶頭像兩個頁面(因為是給予WEB的,所以沒有客戶端的登錄按鈕,只能通過掃碼來登錄)

4ab62eacde669ba2a8854cfd41164d4c.png38b01ad621d34d24ca0caa0272e7a74a.png

在程序啟動以后,先通過請求獲取到二維碼,然后,在啟動一個新的線程,不斷的循環檢索登錄狀態。

private?void?LoopLoginCheck()
{object?login_result?=?null;//循環判斷手機掃描二維碼結果while?(true){login_result?=?ls.LoginCheck();//已掃描?未登錄if?(login_result?is?ImageSource){HeadImageSource?=?login_result?as?ImageSource;//廣播,通知到LoginUC頁面,切換Messenger.Default.Send<object>(null,?"ShowLoginInfoUC");}//已完成登錄if?(login_result?is?string){//訪問登錄跳轉URLls.GetSidUid(login_result?as?string);//廣播,隱藏登錄頁面,打開主頁面Messenger.Default.Send<object>(null,?"HideLoginUC");thread.Abort();break;}超時if?(login_result?is?int){//QRCodeImageSource?=?ls.GetQRCode();//返回二維碼頁面Messenger.Default.Send<object>(null,?"ShowQRCodeUC");}}
}

因為是MVVM,所以,需要用廣播來進行操作頁面的切換,即填充到登錄窗體中間的控件是二維碼,還是頭像。

2、大家可以看到我上面的截圖部分包含了一部分的背景,這個是用Snagit(推薦這個截圖工具,很好用)截圖時,自動截出的,因為窗體本身的大小就是那么大,多余出來的部分是透明的,用來做二維碼滑動出現的效果部分。

c3d009fea9371566fd832bb3abb671a1.gif

當處于二維碼狀態時劃過,則出現動畫,頭像狀態下則沒有動畫,是設置了Image的Visibility屬性來控制的,滑動效果可以看我的另一篇博客微信 二維碼鼠標滑動 圖像顯隱效果[4]

3、當掃碼成功,并且在手機端點擊登錄以后,則跳轉到主頁面,此處沒有加異步等待處理,所以,用戶量大的朋友,請耐心等待(后期會加上)。

5595bfa332890378459fbd56dfadf90d.png

登錄成功以后,就會出現主窗體和系統托盤,主窗體包含最近聯系人和通訊錄,系統托盤網上很多解決方案,可以自行查找。

登錄成功現在發現了一個問題,就是我有兩個微信號,其中一登錄以后是有數據的,另一個則沒有數據。

5850a1b3e7cc41dd6eb8cfdbe567f065.pnga82c65326e0c1fd22e17e7934aa9b0ac.png

跟蹤代碼,發現返回的Json是空的,也就是說沒有返回值,試驗了下周大神的代碼,發現也是空的,不清楚什么情況,我同事的有的也是空的,這個一直沒有深究,等把功能基本都完善以后再看看問題所在。

3f2d7fd06a8e7426c4677f57c611d848.png

二、主窗體模塊

1、主窗體的布局部分很簡單,采用了Grid進行分隔,三列,上面的控件如圖所示

86067a684e3f72718358d7736a8d4939.png

大部分到沒什么,可能大家比較疑惑的是我的聊天窗體為什么是ListBox,這個東西的話,我認為,自己有自己的開發習慣,很多控件都可以實現,panel就可以。

RadioButton的樣式是用path畫的,可以看我另一篇博客微信聊天和通訊錄按鈕樣式[5]

a4995c6801b4f884044d4f6da102efe0.png

2、聊天列表里,未讀的消息上會有帶數字的小紅點,這個是用Button寫的,Item的整體組成是Image(頭像)、Button(未讀數)、TextBlock(昵稱、時間和聊天內容)

<Style?x:Key="ListBoxItemChatStyle"?TargetType="{x:Type?ListBoxItem}"><Setter?Property="Template"><Setter.Value><ControlTemplate?TargetType="ListBoxItem"><Border><StackPanel?x:Name="sp"?Orientation="Horizontal"?Height="{Binding?Converter={StaticResource?objectToHeight}}"?Background="{Binding?Converter={StaticResource?objectToColor}}"><Grid><Image?Source="{Binding?Icon}"?Width="40"?Height="40"?Margin="10"/><Button?Foreground="White"?Visibility="{Binding?UnReadCount,Converter={StaticResource?countToVisibility}}"?Content="{Binding?UnReadCount}"?HorizontalAlignment="Right"?VerticalAlignment="Top"?Margin="0,5"?Style="{StaticResource?CirButtonStyle}"/></Grid><Grid?Width="176"><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><TextBlock?Grid.Row="0"?Text="{Binding?ShowName}"?FontSize="15"?HorizontalAlignment="Left"?Margin="5,10,0,0"/><TextBlock?Grid.Row="0"?Text="{Binding?LastTime}"?FontSize="15"?HorizontalAlignment="Right"?Margin="0,10,5,0"/><TextBlock?Grid.Row="1"?Text="{Binding?LastMsg}"?FontSize="12"?HorizontalAlignment="Left"?Margin="5,0,0,0"/></Grid></StackPanel></Border><ControlTemplate.Triggers><Trigger?Property="IsMouseOver"?Value="true"><Setter?Property="Background"?Value="#FFE2E4E6"?TargetName="sp"/></Trigger><Trigger?Property="IsSelected"?Value="true"><Setter?Property="Background"?Value="#FFCACDD3"?TargetName="sp"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>
d4bd1ca2f65adbcfc18bd19f8771a7a7.png

3、聊天內容部分用的是ScrollingListBox,繼承自ListBox,但是重寫了里面的OnItemsChanged屬性,保證可以時刻滾動到最后一行

public?class?ScrollingListBox?:?ListBox
{protected?override?void?OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs?e){if?(e.NewItems!=null){int?newItemCount?=?e.NewItems.Count;if?(newItemCount?>?0)this.ScrollIntoView(e.NewItems[newItemCount?-?1]);base.OnItemsChanged(e);}????????????}
}

樣式部分是重寫控件模板用的是Image(頭像),path(三角部分),textbox(內容部分)

<Style?x:Key="ChatListBoxStyle"?TargetType="{x:Type?ListBox}"><Setter?Property="Background"?Value="{DynamicResource?{x:Static?SystemColors.WindowBrushKey}}"/><Setter?Property="BorderBrush"?Value="{StaticResource?ListBorder}"/><Setter?Property="BorderThickness"?Value="0"/><Setter?Property="Foreground"?Value="{DynamicResource?{x:Static?SystemColors.ControlTextBrushKey}}"/><Setter?Property="ScrollViewer.HorizontalScrollBarVisibility"?Value="Hidden"/><Setter?Property="ScrollViewer.VerticalScrollBarVisibility"?Value="Hidden"/><Setter?Property="ScrollViewer.CanContentScroll"?Value="true"/><Setter?Property="ScrollViewer.PanningMode"?Value="Both"/><Setter?Property="Stylus.IsFlicksEnabled"?Value="False"/><Setter?Property="VerticalContentAlignment"?Value="Center"/><Setter?Property="ItemContainerStyle"><Setter.Value><Style?TargetType="ListBoxItem"><Setter?Property="Focusable"?Value="False"/><Setter?Property="Template"><Setter.Value><ControlTemplate><StackPanel?Orientation="Horizontal"?Grid.Column="1"?HorizontalAlignment="Stretch"?VerticalAlignment="Top"?FlowDirection="{Binding?FlowDir}"?Margin="15,5"><Image?Grid.Column="1"?Source="{Binding?Image}"?Height="35"?Width="35"?VerticalAlignment="Top"/><Path?Grid.Column="2"?StrokeThickness="1"?Stroke="{Binding?TbColor}"?Data="M12,13?L5,18?L12,23Z"?Fill="{Binding?TbColor}"?Margin="0"?SnapsToDevicePixels="True"/><TextBox?Grid.Column="3"?MaxWidth="355"?TextWrapping="Wrap"?FontSize="15"?BorderBrush="{Binding?TbColor}"?Background="{Binding?TbColor}"?IsReadOnly="True"?BorderThickness="0"?Style="{StaticResource?ChatTextBoxStyle}"?FlowDirection="LeftToRight"?Text="{Binding?Message}"/></StackPanel></ControlTemplate></Setter.Value></Setter></Style></Setter.Value></Setter>
</Style>

需要注意的是:此處必須要重寫控件模板,而不能重寫數據模板,雖然,很多情況下控件模板和數據模板可以得到的效果相同,但是此處,如果寫數據模板的話,則自己發的信息不會在右側,就算設置FlowDirection也沒有用,大家可以自行嘗試。

4、如果發送內容是空的情況下,則會有一個ToolTip出現,此處的TooLTipye也是重寫了樣式的Button,好定位,畢竟就算是最大化,位置也是不變的。

abe13356ab97748634b32d63e22f5e44.png

通訊錄部分,和聊天列表差不多,不過,由于需要進行分組,也就是A、B……這種組合,所以用的Object類型,在點選過程中,通過is來進行判別是不是WeChatUser,如果是,則進行轉換,來進一步處理。

大家可以看到上面那個好友是 同程旅游顧問<span …… 其實它是一個emoji,只是現在我還沒有做到那一部分,如果做到的話,則進行轉換,如果誰有好的emoji處理方式希望告知,謝謝了。

9362930928d2c1bcf13ee860b6d2efde.png5c5764e9fcec0a8508097fbceaa5a99f.png

當點選列表以后,并且轉換成功的情況下,則顯示出用戶的信息,通過內容是否未空,來判別是否要顯示

<Grid?Grid.Row="1"?Grid.RowSpan="2"?HorizontalAlignment="Center"?VerticalAlignment="Center"?Visibility="{Binding?ElementName=rb_friend,Path=IsChecked,Converter={StaticResource?boolToVisibility}}"?Margin="0,50,0,0"><Grid.RowDefinitions><RowDefinition?Height="Auto"/><RowDefinition?Height="Auto"/><RowDefinition?Height="Auto"/><RowDefinition?Height="Auto"/><RowDefinition?Height="Auto"/><RowDefinition?Height="Auto"/><RowDefinition?Height="Auto"/></Grid.RowDefinitions><Image?Source="{Binding?FriendInfo.Icon}"?Grid.Row="0"?Height="124"?Width="124"?HorizontalAlignment="Center"/><StackPanel?Orientation="Horizontal"?Grid.Row="1"?HorizontalAlignment="Center"><TextBlock?Text="{Binding?FriendInfo.NickName}"?FontSize="30"?Foreground="Black"?FontWeight="Bold"/><Image?Visibility="{Binding?FriendInfo.Sex,Converter={StaticResource?parameterToVisibility},ConverterParameter=2}"?Source="/Image/female.png"/><Image?Visibility="{Binding?FriendInfo.Sex,Converter={StaticResource?parameterToVisibility},ConverterParameter=1}"?Source="/Image/male.png"/></StackPanel><TextBlock?Text="{Binding?FriendInfo.Signature}"?Foreground="#FF919191"?Grid.Row="2"?HorizontalAlignment="Center"/><StackPanel?Orientation="Horizontal"?Visibility="{Binding?FriendInfo.RemarkName,Converter={StaticResource?epmtyToVisibility}}"?Margin="10"?Grid.Row="3"?HorizontalAlignment="Center"><TextBlock?Text="備??注"?Margin="0,0,10,0"?FontSize="15"/><TextBlock?Text="{Binding?FriendInfo.RemarkName}"?FontSize="15"/></StackPanel><StackPanel?Orientation="Horizontal"?Visibility="{Binding?FriendInfo.Province,Converter={StaticResource?epmtyToVisibility}}"?Margin="10"?Grid.Row="4"?HorizontalAlignment="Center"><TextBlock?Text="地區"?Margin="0,0,10,0"?FontSize="15"/><TextBlock?Text="{Binding?FriendInfo.Province}"?Margin="0,0,2,0"?FontSize="15"/><TextBlock?Text="{Binding?FriendInfo.City}"?FontSize="15"/></StackPanel><Button?Content="發消息"?Width="166"?Height="37"?Grid.Row="5"?Command="{Binding?FriendSendComamnd}"?Margin="0,50,0,0"?Style="{StaticResource?FriSendButtonStyle}"/><Grid?Grid.Row="0"?Grid.RowSpan="7"?Background="WhiteSmoke"?Visibility="{Binding?FriendInfo,Converter={StaticResource?nullToVisibility}}"/>
</Grid>

點擊發消息按鈕,則跳轉回聊天頁面,然后,將當前的好友加入到聊天的第一項。

三、總結

做WPF微信DEMO,用到了轉換器,轉換顏色,轉換顯隱;重寫了控件的樣式,例如Button、RadioButton、ListBox;然后MVVM模式下,Bind的用法,感覺這個DEOM對于初學者來說應該會有很大的幫助。

不過這個DEMO的BUG和不完善的地方還有很多,例如系統托盤還沒有做閃爍,現在只能發送文字,最大化的問題。

系統托盤閃爍可以用Timer和Opacity來進行控制,比如來未讀消息了,則在進行時間間隔的控制顯隱。

后期會把TextBox換成RichTextBox,這樣可以發送圖片和emoji。

最大化問題,是我一直還沒有想到好的解決辦法,最大化的情況下會占據整個屏幕,而不把狀態欄空出來,網上的辦法都是重新設置Width和Height,但是這樣的話,就要記錄原來的大小和位置,一直沒有找到可以重寫WindowState.Maximized的方法,好像是不能重寫,所以比較糾結,希望哪位大神看完我的代碼以后,能夠給提供一下解決思路,謝謝了。

參考資料

[1]

WEB版微信協議部分功能分析: http://blog.csdn.net/wonxxx/article/details/51787041

[2]

【完全開源】微信客戶端.NET版: http://www.cnblogs.com/xiaozhi_5638/p/4923811.html

[3]

周見智: http://home.cnblogs.com/u/xiaozhi_5638/

[4]

微信 二維碼鼠標滑動 圖像顯隱效果: http://www.cnblogs.com/ZXdeveloper/p/6054278.html

[5]

微信聊天和通訊錄按鈕樣式: http://www.cnblogs.com/ZXdeveloper/p/5997372.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287205.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287205.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287205.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C#字符串、字節數組和內存流間的相互轉換 - IT浪潮之巔

定義string變量為str,內存流變量為ms,比特數組為bt 1.字符串>比特數組 (1)byte[] btSystem.Text.Encoding.Default.GetBytes("字符串");(2)byte[] btConvert.FromBase64String("字符串"); 補充&#xff1a; System.Text.Encoding.Unicode.GetBytes(str)…

ios-新浪微博-下拉刷新獲取最新的消息(解決消息重復的問題)(五)

2019獨角獸企業重金招聘Python工程師標準>>> 第一步 在上一篇博文的基礎上&#xff0c;利用新浪提供的since_id進行判斷&#xff0c;在刷新監聽的方法中&#xff0c;引入下面的代碼 結果如下圖 轉載于:https://my.oschina.net/iOSliuhui/blog/520495

sqlserver快速查找所有存儲過程中是否包含某字符

--將text替換成你要查找的內容 select name from sysobjects o, syscomments s where o.id s.id and text like %text% and o.xtype P --將text替換成你要查找的內容 SELECT ROUTINE_NAME, ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION LI…

《看聊天記錄都學不會Python到游戲實戰?太菜了吧》(7)我用函數寫了個特洛伊木馬

本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋了新手在學習中的一般問題。此系列將會持續更新&#xff0c;包括別的語言以及實戰都將使用對話的方式進行教學&#xff0c;基礎編程語言教學適用于零基礎小白&#xff0c;之后實戰課程也將會逐步更新。 若…

【經典回放】多種語言系列數據結構算法:隊列(C版)

一、隊列ADT以及C語言實現 1 隊列的原理以及ADT分析 隊列是說:把一些數據按先進先出來組織,如同日常生活中的排隊過程。 隊列最主要的操作是 <1> 數據加入隊列;<2> 從隊列中取出數據; 加入隊列只能加入到隊列尾巴上,而從隊列中取出數據、則只能是取出隊列…

linux修改windows注冊表,妙招:讓修改的注冊表立即生效的幾種方法

建站學院(LieHuo.Net)Windows文檔Windows操作系統是全球最廣泛&#xff0c;使用者最多的軟件&#xff0c;熟悉Windows軟件成了電腦操作者必不可少的功課&#xff0c;注冊表作為“Windows的神經系統”非常重要&#xff0c;相信很多朋友都非常熟悉注冊&#xff0c;在開始&#xf…

Android之通過用戶名和密碼連接指定wifi熱點(兼容Android9.0和Android10.0和addNetwork(wifiNewConfiguration)返回-1問題)

1 需求 通過用戶名和密碼連接指定wifi熱點,網上的代碼亂七八糟,沒幾個可以用,我這邊整理了下,測試了華為Android9.0和小米Android9.0和10.0和OPPO Android9.0 都沒問題,直接回調結果就行。 2 問題 在Android10.0手機上 mWifiManager.addNetwork(wifiNewConfiguration);…

hdu 4530(數學)

小Q系列故事——大笨鐘 Time Limit: 600/200 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1458 Accepted Submission(s): 734 Problem Description飽嘗情感苦惱的小Q本打算隱居一段時間&#xff0c;但僅僅在3月25號一天沒有出現&am…

WPF怎么做新手引導界面?

本文經原作者授權以原創方式二次分享&#xff0c;歡迎轉載、分享。原文作者&#xff1a;眾尋原文鏈接&#xff1a;https://www.cnblogs.com/ZXdeveloper/p/8391864.html這兩天不忙&#xff0c;所以&#xff0c;做了一個簡易的新手引導小Demo。因為&#xff0c;不是項目上應用&a…

最全js表單驗證

/***************************************************************** 表單校驗工具類 (linjq) *****************************************************************//** * 判斷整數num是否等于0 * * param num * return * author jiqinlin */function isIntEqZero(num){ r…

《看聊天記錄都學不會C語言?太菜了吧》(19)鞏固開始,數字1、2、3、4能夠組成多少個 3 位數的不同的排列

若是大一學子或者是真心想學習剛入門的小伙伴可以私聊我&#xff0c;若你是真心學習可以送你書籍&#xff0c;指導你學習&#xff0c;給予你目標方向的學習路線&#xff0c;無套路&#xff0c;博客為證。 本系列文章將會以通俗易懂的對話方式進行教學&#xff0c;對話中將涵蓋…

阿里云MaxCompute香港開服 將引入更多人工智能服務

9月18日&#xff0c;阿里云宣布大數據計算服務MaxCompute在香港正式開服。通過MaxCompute強大的計算能力&#xff0c;阿里云將為香港市場提供更多的人工智能產品&#xff0c;助力當地企業智能化升級。據了解&#xff0c;MaxCompute向用戶提供了完善的數據導入方案以及多種經典的…

【經典回放】多種語言系列數據結構算法:串(C版)

我們這里說的串、就是標準的C語言的串,這點,和我們教材中另行定義的串并不一致。我們這里強調僅僅是按C語言的標準處理串,是因為你會按C語言的標準構造串、而不是按其它的模式定義的。在我們的教材上,串相當與一個: struct ElemType {char *str; }; 構造的順序表、或者是…

Android之解決開啟熱點后跳轉頁面不穩定問題

1 問題 在Android8.0版本以后,開啟熱點我們采用的下面這種方式,但是跳轉頁面后熱點會斷開,手機不能互相傳文件了 權限說明:Android8.0需要位置權限和GPS權限,同時手機熱點還不能是開啟狀態。 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {try {mWifiManag…

linux如何獲取網卡計數信息,Linux下如何獲取網卡信息

有時候&#xff0c;寫程序的時候需要獲取計算機的網絡信息&#xff0c;比如IP地址、電腦名稱、DNS等信息。IP地址和電腦名稱是比較容易獲取到的&#xff0c;而要想獲取地址掩碼、DNS、網關等信息就有些麻煩了。在Windows下我們一般都是通過從注冊表讀取這些信息。在Linux怎么做…

Redis命令總結

1.用腳本批量刪除key redis-cli -h 127.0.0.1 keys "MAIN:GAME:GID:*" | xargs redis-cli -h 127.0.0.1 del轉載于:https://www.cnblogs.com/hiwen/p/4900968.html

可以只讀的 ServiceCollection

可以只讀的 ServiceCollectionIntro在 .NET 7 Preview 4 中&#xff0c;ServiceCollection 可以聲明為只讀了&#xff0c;這使得我們可以有效避免在構建了 ServiceProvider 之后再新增服務&#xff0c;導致服務注冊失敗。Sample在新的版本中&#xff0c;ServiceCollection 新增…

阿里云與中國聯通首個公共云平臺上線

11月8日&#xff0c;阿里云與中國聯通關于公共云合作的首個項目&#xff1a;浙江聯通“沃云Powered by Alibaba cloud” 平臺&#xff08;cloud.10010zj.com.cn&#xff09;正式發布上線。該平臺將以沃云品牌為客戶提供“阿里云聯通”服務&#xff0c;結合阿里云技術及浙江聯通…

IBM X System ServerGuide 8.41 服務器 系統安裝 引導盤

IBM X System ServerGuide 8.41 支持操作系統: 32位: Microsoft Windows 2003/2003 R2 (Enterprise, Standard, Web and DataCenter UV) Microsoft Small Business Server 2003/2003 R2 (Standard/Premium Edition) Microsoft Windows 2008 (Enterprise, Standard, Web and Dat…

Matlab R2018b簡體中文版完整安裝圖文教程(附安裝包下載)

目 錄 一、安裝過程 二、下載地址 matlab R2018b安裝包如下所示,包括主程序和補丁文件兩部分。 一、安裝過程 雙擊安裝包中的setup.exe。 選擇使用文件安裝MIYAO,點擊下一步。