この記事は、元の著者の許可を得て、オリジナルの方法で2回共有し、再投稿、共有を歓迎します。
オリジナルタイトル:The Search
原文へのリンク:https//www.cnblogs.com/ZXdeveloper/p/6058206.html
会社の同僚が去り、次の日は忙しくなるかもしれませんし、デモを改善する時間も少なくなりますので、簡単なデモ全体を最初に記録し、その後の継続的な改善を待ちます。
参考两位大神的日志:WEB 版微信协议部分功能分析、【完全开源】微信客户端.NET 版
尤其是周见智大神的 DEMO,因为好多和微信的服务端交互,都借鉴了大神的源码,帮助巨大,可以说我相当于做了一个翻版,只是用 WPF 开发的而已,外观上不同,但是实际交互上是差不多的。
WeChatは2つの部分に分かれており、1つはログインであり、もう1つは本体であり、これに基づいて、WPFは主にこれらの2つのフォームを実装します。
I.ログインモジュール
1、ログイン部分は2次元コードとユーザーアバターの取得の2ページに分かれています(WEBに与えられているため、クライアントのログインボタンがなく、スキャンコードでしかログインできません)。


プログラムが起動した後、最初にリクエストを通じてQRコードを取得し、新しいスレッドを開始してログイン状態を取得します。
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)
{
//访问登录跳转URL
ls.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であるため、ログインフォームの中央に入力されるコントロールがQRコードかアバターかを切り替えるためにブロードキャストが必要です。
2、上記のスクリーンショット部分には背景の一部が含まれていることがわかります。これはSnagit(このスクリーンショットツールをお勧めします、非常に使いやすい)スクリーンショットを使用すると、フォーム自体のサイズがとても大きく、余分な部分は透明で、QRコードスライドの効果部分を行うために使用されます。

当处于二维码状态时划过,则出现动画,头像状态下则没有动画,是设置了 Image 的 Visibility 属性来控制的,滑动效果可以看我的另一篇博客微信 二维码鼠标滑动 图像显隐效果。
3、スキャンスキャンが成功し、携帯電話でログインをクリックした後、メインページにジャンプします。ここでは非同期待機処理が追加されていませんので、大規模なユーザーの友人は、辛抱強く待ってください(後で追加されます)。

ログインが成功すると、メインフォームとシステムトレイが表示され、メインフォームには最近の連絡先とアドレス帳が含まれ、システムトレイは多くのソリューションがオンラインで表示され、自分で見つけることができます。
ログインが成功した今、問題が見つかりました。私は2つのマイクロ信号を持っています。1つはログイン後にデータがあり、もう1つはデータがありません。


コードを追跡すると、返されたJSONが空であることがわかりました。つまり、戻り値がない、来週の神のコードを試してみると、空であることがわかりませんが、私の同僚も空であり、これは深く掘り下げていない、などは基本的に機能を完璧にしてから問題を見てください。

2.メインウィンドウモジュール
メインフォームのレイアウト部分は非常にシンプルで、グリッドで区切られ、3列で、上記のコントロールは図のようになります。

ほとんどは何も、おそらく誰もが私のチャットフォームがなぜListBoxなのか疑問に思うでしょう、このことは、私は自分自身の開発習慣を持っていると思います、多くのコントロールを実装することができ、パネルができます。
RadioButton 的样式是用 path 画的,可以看我另一篇博客微信聊天和通讯录按钮样式

チャットリストでは、未読のメッセージは、ボタンで書かれた数字と小さな赤い点がありますが、アイテムの全体的な構成要素は、画像(アバター)、ボタン(未読み取り)、テキストブロック(ニックネーム、時間、チャットコンテンツ)です。
<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>

チャットコンテンツ部分は、ListBoxから継承されたScrollingList Boxを使用していますが、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也没有用,大家可以自行尝试。
送信内容が空の場合、ToolTipが表示されます。TooLTipyeもスタイルのButtonをオーバーライドしたもので、配置が良いです。結局のところ、最大化されても、位置は変わりません。

アドレス帳部分は,チャットリストとほぼ同じであるが,グループ化,すなわちA,B...という組合せを行う必要があるので,Objectタイプは,クリック中にisでWeChatUserか否かを判別し,そうであれば変換して処理を進める.
大家可以看到上面那个好友是 同程旅游顾问<span …… 其实它是一个 emoji,只是现在我还没有做到那一部分,如果做到的话,则进行转换,如果谁有好的 emoji 处理方式希望告知,谢谢了。


リストがクリックされてから変換が成功した場合には,ユーザの情報が表示され,コンテンツが空でないかどうかで表示するかどうかを判別する.
<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>
メッセージボタンをクリックすると、チャットページに戻り、チャットの最初の項目に現在の友達を追加します。
III.サマリー
WPF WeChat DEMOを行うには、コンバータ、変換色、変換レンダリングを使用します。ボタン、RadioButton、ListBoxなどのコントロールスタイルを書き換えます。MVVMモードでは、Bindの使用は、このDEOMが初心者にとって大きな助けになるはずです。
しかし、このデモのバグや不完全さはまだたくさんあります。例えば、システムトレイはまだ点滅していないので、テキストを送信することができ、問題を最大化することができます。
システムトレイの点滅は、タイマーと不透明度を使用して制御することができます。例えば、未読メッセージが表示され、時間間隔制御が行われます。
Text Boxは後でRichText Boxに置き換えられ、画像や絵文字を送信できるようになった。
最大化の問題は、私はまだ良い解決策を考えていないことです。最大化は、ステータスバーを空にせずに画面全体を占め、オンラインの方法は、幅と高さを再設定することですが、この場合、元のサイズと位置を記録する必要があります、WindowStateを書き換えることができる方法を見つけていませんでした。ありがとうございます。