WPFが開発したWeChatクライアントをご覧ください。

WPFが開発したWeChatクライアントをご覧ください。

WPF WeChat DEMOを行うには、コンバータ、変換色、変換レンダリングを使用します。ボタン、RadioButton、ListBoxなどのコントロールスタイルを書き換えます。MVVMモードでは、Bindの使用は、このDEOMが初心者にとって大きな助けになるはずです。

最后更新 2022/05/20 7:14
眾尋
预计阅读 8 分钟
分类
WPF
标签
.NET WPF MVVM

この記事は、元の著者の許可を得て、オリジナルの方法で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を書き換えることができる方法を見つけていませんでした。ありがとうございます。

源码在这:https://github.com/yanchao891012/WPF_WeChat/

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2024/01/25

C#WPFにおけるFluentValidationの使用

この記事では、C#WPFプロジェクトでFluentValidationをプロパティ検証に使用する方法を詳しく見て、MVVMパターンでこれを実装する方法を示します。

继续阅读
同分类 / 同标签 2023/06/11

7/7

NET Core3環境でMVVMフレームワークPrismのダイアログサービスを使用する方法は、prismシリーズの最後の記事です。

继续阅读
同分类 / 同标签 2023/06/11

6/7

NET Core3でMVVMフレームワークを使用する方法Prism地域ベースのナビゲーションシステム

继续阅读
同分类 / 同标签 2023/06/11

5/7

NET Core3環境でMVVMフレームワークを使用する方法Prismのゾーンマネージャを使用したビューの管理

继续阅读