c#网络通讯之TCP/IP(WPF+PRISM实现)

wpf之Prism框架

使用套接字Socket实现TCP/IP协议

一、Socket通信基本流程

图片来源有菜鸟教程:https://www.cnblogs.com/dotnet261010/p/6211900.html
详细步骤描述:
服务器端:
第一步:创建一个用于监听连接的Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Bind()方法绑定EndPoint;
第四步:用socket对像的Listen()方法开始监听;
第五步:接收到客户端的连接,用socket对像的Accept()方法创建一个新的用于和客户端进行通信的socket对像;
第六步:通信结束后一定记得关闭socket;
客户端:
第一步:建立一个Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;
第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;
第五步:用socket对像的Receive()方法接受服务器发来的信息 ;
第六步:通信结束后一定记得关闭socket;

Note: 同步和异步通信的区别—同步工作方式是指利用TCP编写的程序执行到监听或接收语句时,在未完成工作(侦听到连接请求或收到对方发来的数据)前不再继续往下执行,线程处于阻塞状态,直到该语句完成相应的工作后才继续执行下一条语句。
异步工作方式是指程序执行到监听或接收语句时,不论工作是否完成,都会继续往下执行。

二、代码实现

客户端实现代码:

在这里插入图片描述

视图代码:

<Window x:Class="ClientCode.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="{Binding Title}" Height="350" Width="525" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1.5*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
           
        </Grid.ColumnDefinitions>
        <TextBox Grid.Row="0" Grid.Column="0" BorderBrush="Black" Margin="5"  HorizontalContentAlignment="Left" 
                 Text="{Binding Ip, Mode=TwoWay}"/>
        
        <Border  Margin="5" Grid.Column="1" Grid.Row="0" CornerRadius="10" Background="CadetBlue">
            <TextBox BorderBrush="Black" HorizontalContentAlignment="Left" Text="{Binding Port, Mode=TwoWay}"/>
        </Border>
        
        <Border  Margin="5" Grid.Column="2" Grid.Row="0" CornerRadius="10" Background="CadetBlue">
            <Button BorderBrush="Black" Content="连接服务器" Command="{Binding ConnectedServer}" />
        </Border>
        <Border  Margin="5" Grid.Column="3" Grid.Row="0" CornerRadius="10" Background="CadetBlue">
            <Button BorderBrush="Black" Content="断开服务器" Command="{Binding DisconnectedServer}"/>
        </Border>

        <TextBox Grid.Row="1" Grid.ColumnSpan="5" Background="LightSlateGray" 
                 BorderBrush="Black" Margin="5" Text="{Binding LogText, Mode=TwoWay}"
                 VerticalScrollBarVisibility="Visible"/>
        <TextBox Grid.Row="2" Grid.ColumnSpan="5" Background="LightSlateGray"
                 BorderBrush="Black" Margin="5" Text="{Binding SendText, Mode=TwoWay}"
                 VerticalScrollBarVisibility="Visible"/>

        <Border  Grid.Column="2" Grid.ColumnSpan="4" Grid.Row="3" CornerRadius="5" Background="White">
            <DockPanel Dock="Right" >
                <Button  Content="发送消息" Margin="5" Grid.Column="1" MaxWidth="200" 
                         MinWidth="150" HorizontalAlignment="Right" Command="{Binding SendMessage}"/>
            </DockPanel>
        </Border>
    </Grid>
</Window>

后台逻辑代码:

using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;

namespace ClientCode.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        private string _title = "客户端";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

        private string _ip= "192.168.147.127";
        public string Ip
        {
            get { return _ip; }
            set { SetProperty(ref _ip, value); }
        }

        private string _port="8970";
        public string Port
        {
            get { return _port; }
            set { SetProperty(ref _port, value); }
        }

        private string _logText;
        public string LogText
        {
            get { return _logText; }
            set { SetProperty(ref _logText, value); }
        }


        private string _sendText;
        public string SendText
        {
            get { return _sendText; }
            set { SetProperty(ref _sendText, value); }
        }


        public bool CloseClientThread;   // 用于关闭客户端接收消息线程

        public Socket ClientSocketSend;  //创建连接的Socket

        private Thread CLientThreadReceive;  // 创建客户端接收服务器的线程变量


        public DelegateCommand ConnectedServer { get; private set; }
        public DelegateCommand DisconnectedServer { get; private set; }
        public DelegateCommand SendMessage { get; private set; }

        public MainWindowViewModel()
        {

            ConnectedServer = new DelegateCommand(Client2Server);
            DisconnectedServer = new DelegateCommand(CloseClientFun);
            SendMessage = new DelegateCommand(SendMessageFun);
            
        }

        ///<summary>客户端连接到服务器</summary>>
        private void Client2Server() 
        {
            CloseClientThread = true;
            if (Ip != null && Port != null)
            {
                try
                {
                    ClientSocketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    IPAddress ip = IPAddress.Parse(Ip.Trim());
                    ClientSocketSend.Connect(ip, Convert.ToInt32(Port.Trim()));
                    LogText += "连接成功......" + "\r\n";

                    // 开启循环接收服务器消息的线程
                    CLientThreadReceive = new Thread(new ThreadStart(Receive));
                    CLientThreadReceive.IsBackground = true;
                    CLientThreadReceive.Start();

                }
                catch (Exception ex)
                {
                    LogText += "连接到服务器失败:" + ex.ToString() + "\r\n";
                }

            }
            else 
            {
                LogText += "请输入IP/Port:" + "\r\n";
            }

           
        }


        private void Receive() 
        {
            try
            {
                while (CloseClientThread)
                {
                    byte[] buffer = new byte[2048];
                    //实际接收到的字节数
                    int r = ClientSocketSend.Receive(buffer);
                    if (r == 0)
                    {
                        LogText += "服务端断开连接........." + "\r\n";
                        break;
                    }
                    else
                    {
                        //判断发送的数据的类型
                        if (buffer[0] == 0)  //表示发送的是文字消息
                        {
                            string str = Encoding.Default.GetString(buffer, 1, r - 1);
                            LogText += "接收远程服务器:" + ClientSocketSend.RemoteEndPoint + "发送的消息:" + str + "\r\n";
                        }
                        //表示发送的是文件
                        if (buffer[0] == 1)         // 这里后期改进为WPF中专用的
                        {
                            SaveFileDialog sfd = new SaveFileDialog();
                            sfd.InitialDirectory = @"";
                            sfd.Title = "请选择要保存的文件";
                            sfd.Filter = "所有文件|*.*";
                            sfd.ShowDialog();

                            string strPath = sfd.FileName;
                            using (FileStream fsWrite = new FileStream(strPath, FileMode.OpenOrCreate, FileAccess.Write))
                            {
                                fsWrite.Write(buffer, 1, r - 1);
                            }
                            LogText += "保存文件成功" + "\r\n";
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                LogText += "接收服务端发送的消息出错/与服务器断开连接:" + "\r\n";
            }
        }

        private void SendMessageFun() 
        {
            if (ClientSocketSend != null)
            {
                if (SendText != null)
                    try
                    {
                        string strMsg = SendText.Trim();
                        byte[] buffer = new byte[2048];
                        buffer = Encoding.Default.GetBytes(strMsg);
                        int receive = ClientSocketSend.Send(buffer);

                    }
                    catch (Exception ex)
                    {

                        LogText += "发送消息失败:" + ex.Message + "\r\n";

                    }
                else
                {
                    LogText += "请先输入要发送的信息:" + "\r\n";
                }

            }
            else 
            {
                LogText += "请先连接到服务端:" + "\r\n";
            }
            
        }


        private void SendMessageDisconnect()
        {

            try
            {
                string strMsg = "disconnectNetwork";
                byte[] buffer = new byte[2048];
                buffer = Encoding.Default.GetBytes(strMsg);
                int receive = ClientSocketSend.Send(buffer);

            }
            catch (Exception ex)
            {

                LogText += "发送断开连接消息出错:" + ex.Message + "\r\n";

            }
          
        }


        private void CloseClientFun() 
        {

            // 发送消息告诉服务端,我将断开连接;如果客户端主动断开与服务端的连接,
            // 最好实现让服务端接收消息的线程函数退出循环阻塞状态,不然会引发服务端异常:

            // System.Net.Sockets.SocketException: 您的主机中的软件中止了一个已建立的连接。   
            //An established connection was aborted by the software in your host machine

            SendMessageDisconnect();

            if (ClientSocketSend != null)
            {

                //终止线程
                CloseClientThread = false;

                //关闭socket
                ClientSocketSend.Close(); 
            }
            else 
            {
                LogText += "客户端未开启" + "\r\n";
            }
        }
    }
}

服务端代码

在这里插入图片描述

1、 视图代码

<Window x:Class="ServerCode.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="{Binding Title}" Height="350" Width="542" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="4*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1.5*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>
        <TextBox Grid.Row="0" Grid.Column="0" BorderBrush="Black" Margin="5" Text="{Binding Ip}" HorizontalContentAlignment="Left"/>
        <Border  Margin="5" Grid.Column="1" Grid.Row="0" CornerRadius="10" Background="CadetBlue">
            <TextBox BorderBrush="Black" Text="{Binding Port,Mode=TwoWay}" HorizontalContentAlignment="Left"/>
        </Border>
        <Border  Margin="5" Grid.Column="2" Grid.Row="0" CornerRadius="10" Background="CadetBlue">
            <Button BorderBrush="Black" Content="开始监听" Command="{Binding StartListen}"/>
        </Border>
        <Border  Margin="5" Grid.Column="3" Grid.Row="0" CornerRadius="10" Background="CadetBlue">
            <Button BorderBrush="Black" Content="停止监听" Command="{Binding StopListen}"/>
        </Border>
        <Border  Margin="5" Grid.Column="4" Grid.Row="0" CornerRadius="10">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="连接的客户:" VerticalAlignment="Center" TextAlignment="Center"/>
                <ComboBox Width="80" ItemsSource="{Binding DicSocket,Mode=TwoWay}" SelectedValuePath="ItemSocket" DisplayMemberPath="ip" 
                          SelectedValue="{Binding SelectSocket,Mode=TwoWay}"  />
            </StackPanel>
        </Border>

        <TextBox Grid.Row="1" Grid.ColumnSpan="5" Background="LightSlateGray" 
                 BorderBrush="Black" Margin="5" Text="{Binding LogReceive}" VerticalScrollBarVisibility="Visible"/>
        <TextBox Grid.Row="2" Grid.ColumnSpan="5" Background="LightSlateGray" 
                 BorderBrush="Black" Margin="5" Text="{Binding Sendtext}" VerticalScrollBarVisibility="Visible"/>
        
        <Border  Margin="5" Grid.ColumnSpan="2" Grid.Row="3" CornerRadius="10" Background="CadetBlue">
            <TextBox BorderBrush="Black" Text="{Binding SelectFile,Mode=TwoWay}"/>
        </Border>

        <Border  Grid.Column="2" Grid.ColumnSpan="4" Grid.Row="3" CornerRadius="5" Background="White">
            <StackPanel Orientation="Horizontal" >
                <Grid Width="323">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Button  Content="选择文件" Margin="5" Grid.Column="0" Command="{Binding SelectCommand}"/>
                    <Button  Content="发送文件" Margin="5" Grid.Column="1" Command="{Binding SendFileCommand}"/>
                    <Button  Content="发送消息" Margin="5" Grid.Column="2" Command="{Binding SendMessageCommand}"/>
                </Grid>

            </StackPanel>
        </Border>
    </Grid>
</Window>

2、 服务端业务代码

using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace ServerCode.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        private string _title = "服务端";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

        private string _ip="192.168.178.208";
        public string Ip
        {
            get { return _ip; }
            set { SetProperty(ref _ip, value); }
        }

        private string _port = "8970";
        public string Port
        {
            get { return _port; }
            set { SetProperty(ref _port, value); }
        }

        private string _selectFile;
        public string SelectFile
        {
            get { return _selectFile; }
            set { SetProperty(ref _selectFile, value); }
        }

        private string _logReceive;
        public string LogReceive
        {
            get { return _logReceive; }
            set { SetProperty(ref _logReceive, value); }
        }

        private string _sendtext;
        public string Sendtext
        {
            get { return _sendtext; }
            set { SetProperty(ref _sendtext, value); }
        }

       
        private SynchronizedCollection<IpSocket> _dicSocket;    // 一个集合关于连接到服务端的客户端套接字(IP地址和SOCKET)
        public SynchronizedCollection<IpSocket> DicSocket
        {
            get { return _dicSocket; }
            set { SetProperty(ref _dicSocket, value);
                RaisePropertyChanged();
            }
        }

        private Socket _selectSocket;
        public Socket SelectSocket
        {
            get { return _selectSocket; }
            set { SetProperty(ref _selectSocket, value); }
        }



        public DelegateCommand StartListen { get; private set; }          // 开始监听命令


        public DelegateCommand StopListen { get; private set; }            // 停止监听命令


        public DelegateCommand SelectCommand { get; private set; }         // 选择文件命令


        public DelegateCommand SendFileCommand { get; private set; }        // 发送文件命令


        public DelegateCommand SendMessageCommand { get; private set; }     // 发送消息命令

        public Socket socketWatch;                     // 用于监听的Socket
        public Socket socketSend;                      // 用于通信的Socket


        Thread AcceptSocketThread;                    // 创建监听连接得线程,接收消息的线程

        Thread threadReceive;                         // 接收客户端发送消息的线程

        public bool AcceptSocketBool;
        public bool ThreadReceiveBool;


        public MainWindowViewModel()
        {

            DicSocket = new SynchronizedCollection<IpSocket>();

            StartListen = new DelegateCommand(startListen);

            StopListen = new DelegateCommand(StopListenFun);

            SelectCommand = new DelegateCommand(SelectFileFun);

            SendFileCommand = new DelegateCommand(SendFilesFun);

            SendMessageCommand = new DelegateCommand(Server2Client);

        }

        // 开始监听并接收客户端发送的消息
        public void startListen() 
        {
            ThreadReceiveBool = true;
            AcceptSocketBool = true;
            if (socketWatch == null)
            {
                try
                {
                    // step1: 在服务器端创建一个负责监听IP地址和端口号的Socket
                    socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                    IPAddress ip = IPAddress.Parse(Ip.Trim());      // step2: 获取IP地址

                    IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(Port.Trim()));    // step3: 获取Port

                    socketWatch.Bind(point);             // step4: 给服务器端的SOCKET绑定IP和Port

                    socketWatch.Listen(10);               // step5: 开始监听,并指定最大监听客户端的个数为10

                    LogReceive += "服务端:监听开启,等待客户端的连接........" + "\r\n";

                    // 等待客户端的连接,如果连接成功,就将客户端的Socket和对应的IP地址加入到监听集合中,并开启消息接收线程
                    AcceptSocketThread = new Thread(new ParameterizedThreadStart(StartListenFunc));
                    AcceptSocketThread.IsBackground = true;
                    AcceptSocketThread.Start(socketWatch);
                }

                catch (Exception ex)
                {
                    LogReceive += ex.ToString() + "\r\n";
                }
            }
            else 
            {
                LogReceive += "服务器端已开启监听:" + "\r\n";
            }
           
                                            
        }
        ///<summary>获取远程连接得Socket和IP地址,同时实现客户端消息的接收</summary>
        private void StartListenFunc(object obj) 
        {
            Socket socketWatch = obj as Socket;
            while (AcceptSocketBool)
            {
                try
                {
                    // 等待客户端的连接,并且创建一个用于通信的Socket,这里只能是一个全局唯一变量的Socket类型
                    socketSend = socketWatch.Accept();

                    if (socketSend != null)
                    {
                        // 获取远程主机的ip地址和端口号
                        string strIp = socketSend.RemoteEndPoint.ToString();
                        if (JudgeHave(strIp)) 
                        {
                            IpSocket perClient = new IpSocket();
                            perClient.ip = strIp;
                            perClient.ItemSocket = socketSend;

                            // 这里要加一个判断条件,如果已经存在的客户端不能够添加进来

                            DicSocket.Add(perClient);

                            LogReceive += "远程主机:" + socketSend.RemoteEndPoint + "连接成功" + "\r\n";

                            // 定义接收客户端消息接收的线程
                            threadReceive = new Thread(new ParameterizedThreadStart(ReceiveMessage));
                            threadReceive.IsBackground = true;
                            threadReceive.Start(socketSend);
                        }
                    }
                    else 
                    {
                        LogReceive = "客户端断开连接/服务端停止监听" + "\r\n";
                    }
                }
                catch 
                {
                    LogReceive = "客户端断开连接/服务端停止监听" + "\r\n";
                }

               
            }
        
        }

        /// <summary>
        /// 用于判断最新监听到的客户端连接请求,在服务端是否已近为其创建了接收消息线程,若存在则不再为其创建接收消息线程
        /// </summary>
        /// <param name="ip">服务端最新监听到的客户端请求连接得ip地址</param>
        /// <returns>true表示不存在,可以创建接收线程。false表示存在,不为其创建接收线程</returns>
        private bool JudgeHave(string ip) 
        {
            if (DicSocket.Count > 0)
            {
                foreach (IpSocket PerClient in DicSocket)
                {
                    if (PerClient.ip == ip)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
            }
            return true;
   
        }


        /// <summary>服务器端不停的接收客户端发送的消息</summary>
        private void ReceiveMessage(object obj) 
        {
            Socket socketSendLocal = obj as Socket;
            while (ThreadReceiveBool) 
            {
                //客户端连接成功后,服务器接收客户端发送的消息
                byte[] buffer = new byte[2048];
                //实际接收到的有效字节数
                int count = socketSendLocal.Receive(buffer);
                //count 表示客户端关闭,要退出循环
                if (count == 0)
                {
                    LogReceive += "客户端:" + socketSendLocal.RemoteEndPoint + "断开连接...." +"\r\n";
                    break;
                }
                else 
                {
                    string str = Encoding.Default.GetString(buffer, 0, count);
                    string strReceiveMsg = "接收:" + socketSendLocal.RemoteEndPoint + "发送的消息:" + str;
                    LogReceive += strReceiveMsg + "\r\n";

                    if (str == "disconnectNetwork") 
                    {
                        // 当客户端与服务器断开连接后,需要更新DicSocket列表数据,下面代码可以更改为条件查询语句进行优化
                        for(int i=0; i < DicSocket.Count; i++) 
                        {
                            if (DicSocket[i].ip == socketSendLocal.RemoteEndPoint.ToString()) 
                            {
                                DicSocket.RemoveAt(i);
                            }
                        }

                        LogReceive += socketSendLocal.RemoteEndPoint.ToString() + "断开连接" + DicSocket.Count + "\r\n";
                        break;
                    }

                }

            }
        }


        ///<summmary>服务器给客户端发送消息</summmary>>

        private void Server2Client() 
        {
          
            if (Sendtext != null && SelectSocket!=null)
            {

                string strMessage = Sendtext.Trim();
                byte[] buffer = Encoding.Default.GetBytes(strMessage);
                List<byte> list = new List<byte>();
                list.Add(0);
                list.AddRange(buffer);
                //将泛型集合转换为数组
                byte[] newBuffer = list.ToArray();

                //获得用户选择的IP地址  ? 如何获取itemControl的选项
                try
                {
                    //string ip = SelectIp.ToString();
                    //DicSocket[SelectIp.ToString()].Send(newBuffer);
                    SelectSocket.Send(newBuffer);
                }
                catch (Exception ex)
                {
                    LogReceive += "向客户端发送消息发生异常:" + ex.ToString() + "\r\n";
                }
            }
            else 
            {
                LogReceive += "请输入发送的消息/选择发送客户端对象...." + "\r\n"; 
            }
           
        }


        ///<summary>选择要发送的文件</summary>
        private void SelectFileFun() 
        {
            OpenFileDialog dia = new OpenFileDialog();
            //设置初始目录
            dia.InitialDirectory = @"";
            dia.Title = "请选择要发送的文件";
            //过滤文件类型
            dia.Filter = "所有文件|*.*";
            dia.ShowDialog();
            //将选择的文件的全路径赋值给文本框
            SelectFile = dia.FileName;
        }


        ///<summary>发送文件</summary>
        private void SendFilesFun() 
        {
            List<byte> list = new List<byte>();
            //获取要发送的文件的路径
            string strPath = SelectFile.Trim();
            using (FileStream sw = new FileStream(strPath, FileMode.Open, FileAccess.Read)) 
            {
                byte[] buffer = new byte[2048];
                int r = sw.Read(buffer, 0, buffer.Length);
                list.Add(1);
                list.AddRange(buffer);
                byte[] newBuffer = list.ToArray();
               
                try
                {
                    SelectSocket.Send(newBuffer, 0, r + 1, SocketFlags.None);
                }
                catch (Exception ex) 
                {
                    LogReceive += "文件发送异常:" + ex.ToString() + "\r\n";
                }
            }
           
        }



        ///<summary>停止监听</summary>>
        private void StopListenFun() 
        {
            if (ThreadReceiveBool && AcceptSocketBool)
            {

                if (socketWatch==null) 
                {
                     LogReceive += "服务器还未启动......" + "\r\n"; 
                }
                else
                {
                    ThreadReceiveBool = false;
                    AcceptSocketBool = false;
                    if (socketSend != null) socketSend.Close();
                    if (socketWatch!=null) socketWatch.Close();
                }
            }
            else 
            {
                LogReceive += "服务器还未启动:" + "\r\n";
            }
        }
    }
}

结果展示(多客户端连接测试):

在这里插入图片描述

客户端工程目录:
在这里插入图片描述
服务端工程目录:
在这里插入图片描述

参考资源地址:

基础版本代码与概念参考地址: https://www.cnblogs.com/dotnet261010/p/6211900.html
代码调试参考地址: https://www.cnblogs.com/chucklu/p/5421246.html
源代码压缩包地址: https://download.csdn.net/download/xiaochuideai/86398577

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: WPF是一种基于XAML语言的用户界面开发框架,使开发人员能够轻松创建漂亮和高效的桌面应用程序。MVVM是一种模式,它在WPF应用程序中广泛使用,它提供了一种分离UI和业务逻辑的方式,从而简化了代码结构。Prism是一个开源框架,它基于MVVM模式和WPF框架,提供了一些技术和工具,使开发人员能够更轻松地构建复杂的WPF应用程序。 使用WPF MVVM Prism框架可以帮助开发人员提高应用程序的可维护性和可扩展性。通过MVVM,开发人员可以创建一个适应各种应用程序场景的模型,并将其与UI分离。数据绑定和命令绑定使开发人员能够更轻松地将模型中的数据和逻辑与UI控件集成起来。Prism框架还提供了一些工具和功能,如模块化应用程序开发、事件聚合器、导航、对话框、异常处理等功能。这些工具使开发人员能够更轻松地构建复杂的应用程序,并提供了一种可扩展和可重用的方法。 总之,使用WPF MVVM Prism可以使开发人员更轻松地构建复杂的应用程序,并提高应用程序的可维护性和可扩展性。开发人员可以根据自己的需求选择使用这个框架来开发WPF应用程序,从而提高他们的工作效率和代码质量。 ### 回答2: WPF MVVM Prism是一种基于Windows Presentation Foundation(WPF)的软件开发模式,采用了MVVM(Model-View-ViewModel)设计模式和Prism框架来实现软件开发。MVVM是一种在WPF应用程序中使用的设计模式,它将应用程序的视图(View)与应用程序的模型(Model)分离开来,通过ViewModel来连接二者。Prism是一个帮助开发人员编写出复杂、可管控、可扩展和可维护的WPF应用程序的框架。 WPF MVVM Prism提供了很多好处:首先,它能实现软件的可重用性,通过将代码和视图分离,使得代码可以在多个不同的视图中重复使用,提高了开发效率。其次,它可以提高软件的可维护性,通过将逻辑和视图分离,确保逻辑代码与UI代码之间更少的耦合,提高了软件的可扩展性。此外,它还可以提高软件的可测试性,由于MVVM模式中将视图和逻辑分离开,所以开发人员可以更容易地编写出单元测试代码,来测试逻辑代码。最后,由于Prism框架提供了一些通用的,可定制的模块和服务,使得开发人员可以更快地实现常见功能、缩短开发时间。 总之,WPF MVVM Prism是一种高效、可扩展和易于维护的软件开发模式,它将视图和逻辑分离,提高了软件的可重用性和可测试性,同时也提高了软件的可扩展性和可复用性。 ### 回答3: WPF是一种桌面应用程序框架,它允许您为Windows创建高度交互式和可视化的应用程序界面。MVVM是一种软件编程模式,它将用户界面(UI)与业务逻辑分离,以便更好地实现可维护,可扩展和可组合的代码。Prism是一个WPF和Silverlight应用程序的组件库,它提供了一些可重用和可扩展的基础设施组件,帮助您更快速地构建、测试和维护WPF应用程序。因此,WPF MVVM Prism的组合可以帮助您更轻松高效地开发WPF应用程序。您可以使用MVVM模式来改进应用程序的结构和测试,使用Prism来更好地组织和可扩展您的代码,以及使用WPF实现交互丰富的UI。同时还可以使用Prism提供的事件聚合器、导航器和模块化架构,实现更灵活的应用程序设计。WPF MVVM Prism的组合提供了一种更有效的方式来构建WPF应用程序,以满足现代用户体验的需求,并且更容易测试和维护,因此它已成为WPF应用程序开发的重要组合。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值