网络编程(2)

08 并行

并行串行计算比较

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace test07
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void bt_Click(object sender, RoutedEventArgs e)
        {
            long[] t1 = await Task.Run(() => Multiply(200, 18, 27));
            tb.Text = string.Format("测试1(矩阵1:200x18,矩阵2:18x27),非并行用时{0}毫秒,并行用时{1}毫秒\n", t1[0], t1[1]);
            long[] t2 = await Task.Run(() => Multiply(2000, 180, 270));
            tb.Text += string.Format("测试1(矩阵1:2000x180,矩阵2:180x270),非并行用时{0}毫秒,并行用时{1}毫秒\n", t2[0], t2[1]);
            long[] t3 = await Task.Run(() => Multiply(2000, 200, 300));
            tb.Text += string.Format("测试1(矩阵1:2000x200,矩阵2:200x300),非并行用时{0}毫秒,并行用时{1}毫秒\n", t3[0], t3[1]);

        }

        /// <summary>
        /// 传入行数和列数,初始化一个矩阵
        /// </summary>
        /// <param name="rows"></param>
        /// <param name="cols"></param>
        /// <returns></returns>
        public static int[,] InitializeMatrix(int rows, int cols)
        {
            int[,] matrix = new int[rows, cols];
            Random r = new Random();
            for(int i = 0; i < rows; i++)
            {
                for(int j = 0; j < cols; j++)
                {
                    matrix[i, j] = r.Next(100);
                }
            }
            return matrix;
        }
        /// <summary>
        /// 普通方法计算矩阵乘法
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        public static void CommonCompute(int[,] a,int[,] b)
        {
            int arows = a.GetLength(0);
            int acols = a.GetLength(1);
            int bcols = b.GetLength(1);
            int[,] result = new int[arows, bcols];
            for(int i = 0; i < arows; i++)
            {
                for(int j = 0; j < bcols; j++)
                {
                    int temp = 0;
                    for (int k = 0; k < acols; k++)
                    {
                        temp += a[i, k] * b[k, j];
                    }
                    result[i, j] = temp;
                }
            }
        }
        /// <summary>
        /// 并行方法计算矩阵乘法
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        public static void ParallelCompute(int[,] a, int[,] b)
        {
            int arows = a.GetLength(0);
            int acols = a.GetLength(1);
            int bcols = b.GetLength(1);
            int[,] result = new int[arows, bcols];
            Action<int> action = i =>
            {
                for (int j = 0; j < bcols; j++)
                {
                    int temp = 0;
                    for (int k = 0; k < acols; k++)
                    {
                        temp += a[i, k] * b[k, j];
                    }
                    result[i, j] = temp;
                }
            };
            //外循环并行执行
            Parallel.For(0, arows, action);     
        }
        /// <summary>
        /// 计算矩阵乘法
        /// </summary>
        /// <param name="rows"></param>
        /// <param name="cols"></param>
        /// <param name="cols2"></param>
        /// <returns></returns>
        public static long[] Multiply(int rows,int cols,int cols2)
        {
            //初始化矩阵
            int[,] a = InitializeMatrix(rows, cols);
            int[,] b = InitializeMatrix(cols, cols2);

            Stopwatch watch = new Stopwatch();
            long[] timeElapsed = new long[2];
            //串行
            watch.Start();
            CommonCompute(a, b);
            watch.Stop();
            timeElapsed[0] = watch.ElapsedMilliseconds;
            //并行
            watch.Restart();
            ParallelCompute(a, b);
            watch.Stop();
            timeElapsed[1] = watch.ElapsedMilliseconds;
            return timeElapsed;
        }
    }
}

在这里插入图片描述

09 新建WCF架构程序

  • 1.新建WCF服务应用程序(或服务库),并设计服务程序。2.新建客户端程序(可以是wpf,控制台等),直接修改命名(~Client)。3.客户端程序添加服务引用(如果是在同一解决方案下,直接点“发现”,相当于把服务端的接口下载下来了,所以如果服务端修改程序的话(目前看包括接口的修改和接口实现的修改),必须要调试一下,“保存”,然后客户端需要重新添加服务引用。
  • 1.新建WCF服务应用程序(或服务库),并设计服务程序。
 [OperationContract]
        string GetData(int value);
        [OperationContract]
        //启动进程
        bool StartProcess(string processName);
        [OperationContract]
        //删除文件
        bool DeleteFile(string path);
        [OperationContract]
        //获取文件信息
        string ReadFile(string path);
        [OperationContract]
        //修改变量值
        void Change(ref string s);
        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);

方法实现:

public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
        public bool StartProcess(string processName)
        {
            try
            {
                Process.Start(processName);
                return true;
            }
            catch (Exception)
            {
                return false;
            }  
        }
        public bool DeleteFile(string path)
        {
            try
            {
                File.Delete(path);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        public string ReadFile(string path)
        {
            string str, s;
            str = "";
            try
            {
                FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
                StreamReader sr = new StreamReader(fs);
                while ((s = sr.ReadLine()) != null)
                {
                    str += s;
                }
                fs.Close();
                sr.Close();
            }
            catch (Exception)
            {
                s = "读取失败";
            }
            return str;
        }
        public void Change(ref string s)
        {
            s = "changed";
        }
  • 步骤2
    新建客户端,添加服务引用
    界面设计:
    在这里插入图片描述
    功能实现;
private  void bt_Click(object sender, RoutedEventArgs e)
        {
            Button currentbuttton = sender as Button;
            string s = currentbuttton.Content.ToString();
            if (s == "start")
            {
                StartProcess();
            }
            else if (s == "delete")
            {
                DeleteFile();
            }
            else if (s == "get")
            {
                ReadFile();
            }
            else if (s == "change")
            {
                Change();
            }
        }
        
        //启动进程
        public async void StartProcess()
        {
            Service1Client client = new Service1Client();
            string processname = tbprocess.Text;
            bool b = await Task<bool>.Run(() => client.StartProcess(processname));
            if (b)
                MessageBox.Show("启动进程成功!");
            else
                MessageBox.Show("启动进程失败!");
        }
        //删除文件
        public async void DeleteFile()
        {
            Service1Client client = new Service1Client();
            string path = tbdeleteFilePath.Text;
            bool b = await Task<bool>.Run(() => client.DeleteFile(path));
            if (b)
                MessageBox.Show("删除成功!");
            else
                MessageBox.Show("删除失败!");
        }
        //获取文件信息
        public async void ReadFile()
        {
            Service1Client client = new Service1Client();
            string path = tbreaddFilePath.Text;
            string s = await Task<string>.Run(() => client.ReadFile(path));
            MessageBox.Show("读取内容:"+s);
        }
        //修改变量值
        public async void Change()
        {
            Service1Client client = new Service1Client();
            string s = tb.Text;
            await Task.Run(() => client.Change(ref s));
            tb.Text = s;
        }
    }
  • 问题与解决
    1.读取文件方法执行后无法打开文件
    解决:忘了关闭流
    2.删除文件时界面卡死
    解决:文件路径里的“/”应该是换成“\”,然后意识到应该做异步编程。

  • 一些比较复杂的类不能序列化(比如返回值是process类),可以自己新建类,给类加上数据协定,给类里面的属性也添加。

10 视频绘制

主要就是动态绘制类和静态绘制类,然后绑定到inkcanvas和radio button上。
基于矩形绘制来写视频绘制。

  • 添加视频素材,直接把文件复制过来,右键,包含在项目中,对视频的属性设置为“复制到输出目录:始终复制”。
  • 设计界面加上“视频”的按钮
  • mainwindow.cs
private void RibbonRadioButton_Checked(object sender, RoutedEventArgs e)
        {
            RibbonRadioButton rrb = e.Source as RibbonRadioButton;
            string rrbLabel = rrb.Label;
            switch (rrbLabel)
            {
                case "球形":
                    myinkcanvas.selectShape = "球形";
                    InkEllipseDynamic myDynamic1 = new InkEllipseDynamic();
                    myinkcanvas.setDyanmic(myDynamic1);
                    break;
                case "矩形":
                    myinkcanvas.selectShape = "矩形";
                    InkRectangleDynamic myDynamic2 = new InkRectangleDynamic();
                    myinkcanvas.setDyanmic(myDynamic2);
                    break;
                case "图像":
                    myinkcanvas.selectShape = "图像";
                    //InkRectangleDynamic myDynamic2 = new InkRectangleDynamic();
                    //myinkcanvas.setDyanmic(myDynamic2);
                    break;
                case "视频":
                    myinkcanvas.selectShape = "视频";
                    InkViedoDynamic myDynamic3 = new InkViedoDynamic();
                    myinkcanvas.setDyanmic(myDynamic3);
                    break;
            }

myinkcanvas.setDyanmic(myDynamic3);
myinkcanvas

 public void setDyanmic(DynamicRenderer d1)
        {
            this.DynamicRenderer = d1;
        }
  • 动态绘制类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Media;

namespace InkDrawExample.MyInks
{
    class InkViedoDynamic : DynamicRenderer
    {
        public Point firstPoint;
        public string uriString = @"Videos\Video1.wmv";
        public MediaPlayer p;
        protected override void OnStylusDown(RawStylusInput rawStylusInput)
        {
            base.OnStylusDown(rawStylusInput);
            firstPoint = (Point)rawStylusInput.GetStylusPoints().First();
                p = new MediaPlayer();
                p.Open(new Uri(uriString, UriKind.Relative));
                p.IsMuted = true; //把视频静音
                p.MediaEnded += (s, e) => { p.Position = TimeSpan.Zero; };
                p.Play();//开始播放视频 
        }
        protected override void OnStylusMove(RawStylusInput rawStylusInput)
        {
            base.OnStylusMove(rawStylusInput);
            StylusPointCollection stylusPoints = rawStylusInput.GetStylusPoints();
            this.Reset(Stylus.CurrentStylusDevice, stylusPoints);
        }

        protected override void OnStylusUp(RawStylusInput rawStylusInput)
        {
            p.Stop();
            p.Close();//关闭动态绘制时的媒体播放视频
            base.OnStylusUp(rawStylusInput);
        }

        protected override void OnDraw(DrawingContext drawingContext, StylusPointCollection stylusPoints, Geometry geometry, Brush fillBrush)
        {
            Point lastPoint = (Point)stylusPoints.Last();
            Vector v = Point.Subtract(lastPoint, firstPoint);
            Rect rect = new Rect(firstPoint, v);
            drawingContext.DrawVideo(p,rect);
        }
    }
}

因为视频加载播放会消耗资源,所以放在 OnStylusDown 里。
墨迹也会重新绘制视频,所以要在OnStylusUp 里把动态绘制时的视频关闭。

  • 静态绘制类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Media;

namespace InkDrawExample.MyInks
{
    class InkViedoStroke : Stroke
    {
        public static  MediaPlayer p;
        public string uriString = @"Videos\Video1.wmv";
        public InkViedoStroke(StylusPointCollection stylusPoints)
            : base(stylusPoints)
        {
        }

        public static void CreateVideoPlayer(string uriString)
        {
            p = new MediaPlayer();
            p.Open(new Uri(uriString, UriKind.Relative));
            p.IsMuted = true; 
            p.MediaEnded += (s, e) => { p.Position = TimeSpan.Zero; };
            p.Play();//开始播放视频 
        }


        protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
        {
            Point firstPoint = (Point)this.StylusPoints.First();
            Point lastPoint = (Point)this.StylusPoints.Last();
            Vector v = Point.Subtract(lastPoint, firstPoint);
            Rect rect = new Rect(firstPoint, v);
            CreateVideoPlayer(uriString);
            drawingContext.DrawVideo(p, rect);
        }
    }
}

先写DrawCore方法:根据动态绘制时的StylusPoints,设定好绘制矩形的形状, 用drawingContext.DrawVideo(p, rect); 绘制视频。所以需要一个meidaplayer,从动态绘制类里复制过来。

  • 绑定到myinkcanvas
 protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
        {
            switch (selectShape)
            {
                case "球形":
                    this.Strokes.Remove(e.Stroke);
                    InkEllipseStroke stroke1 = new InkEllipseStroke(e.Stroke.StylusPoints);
                    this.Strokes.Add(stroke1);
                    break;
                case "矩形":
                    this.Strokes.Remove(e.Stroke);
                    InkRectangleStroke stroke2 = new InkRectangleStroke(e.Stroke.StylusPoints);
                    this.Strokes.Add(stroke2);
                    break;
                case "图像":
                    this.Strokes.Remove(e.Stroke);
                    //构造静态呈现对象
                    //添加到this.Strokes.Add();
                    break;
                case "视频":
                    this.Strokes.Remove(e.Stroke);
                    InkViedoStroke stroke3 = new InkViedoStroke(e.Stroke.StylusPoints);
                    this.Strokes.Add(stroke3);
                    break;
            }
        }
        public void setDyanmic(DynamicRenderer d1)
        {
            this.DynamicRenderer = d1;
        }

11.WCF和HTTP文件传输

  • 服务端
    .cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace downloadfiles
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。
    [ServiceContract]
    public interface IService1
    {

        [OperationContract]
        List<string> GetFilesInfo();
        [OperationContract]
        Stream DownloadStream(string fileName);

    }

}

.svc.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace downloadfiles
{

    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“Service1”。
    // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 Service1.svc 或 Service1.svc.cs,然后开始调试。
    public class Service1 : IService1
    {
        public static List<string> filesInfo;
        public static string path;

        public List<string>  GetFilesInfo()
        {
            if (filesInfo == null)
            {
                filesInfo = new List<string>();
                path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "download");
                DirectoryInfo di = new DirectoryInfo(path);
                var q = di.GetFiles();
                foreach(var i in q)
                {
                    filesInfo.Add(string.Format("{0},{1}", i.Name, i.Length));
                }
            }
            return filesInfo;
        }

        public Stream DownloadStream(string fileName)
        {
            string filePath = System.IO.Path.Combine(path, fileName);
            try
            {
                FileStream imageFile = File.OpenRead(filePath);
                return imageFile;
            }
            catch (IOException EX)
            {

                throw EX;
            }
        }
    }
}

web.congfig 修改使传输容量更大

<bindings>
      <basicHttpBinding>
        <!--67108864的含义是64MB,这是HTTP每次传输允许的最大值(不指定时默认值为64KB)
            用HTTP实现时,如果希望下载大文件(例如2GB),需要先将文件按64MB切分,
            客户端分别下载后,最后再将其合并为一个文件。
            另外,也可以用TCP提供下载功能,用TCP实现时可通过配置直接下载不大于4GB的文件,
            具体实现见MSDN中的相关说明-->
        <binding name="HttpStreaming" maxReceivedMessageSize="671088640" transferMode="Streamed"/>
      </basicHttpBinding>
    </bindings>
  • 客户端
    界面设计
    在这里插入图片描述
using Client.ServiceReference1;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Client
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public static string[] filesInfo;
        public MainWindow()
        {
            InitializeComponent();
            Service1Client client = new Service1Client();
            filesInfo = client.GetFilesInfo();
            foreach (string i in filesInfo)
            {
                string[] split = i.Split(',');
                lb.Items.Add(string.Format("文件名:{0},字节长度:{1}", split[0], split[1]));
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            int n = lb.SelectedIndex;
            if (n != -1)
            {
                string[] s = filesInfo[n].Split(',');
                string fileName = s[0];
                string fileSize = s[1];
                Service1Client client = new Service1Client();
                Stream imageFile = client.DownloadStream(fileName);
                tb.Text += "正在下载" + fileName + "\n";

                //读取
                byte[] buffer = new byte[1024];//设置缓冲区
                string path = @"E:\study\大二下\网络编程\作业\WCF和HTTP文件传输\downloadfiles\" + fileName;
                //目标文件流
                FileStream fsNew = new FileStream(path, FileMode.Create, FileAccess.ReadWrite);
                int num;
                int sum = 0;
                while ( (num=imageFile.Read(buffer, 0, buffer.Length)) > 0)
                {
                    sum += num;
                    //写入目标文件流
                    fsNew.Write(buffer, 0, num);
                }
                //一定要关闭流,如果没有关闭,在此程序外就无法对文件进行操作
                imageFile.Close();
                fsNew.Close();
                tb.Text += "下载完成,共下载" + sum + "字节," + "文件保存到" + path;

            }
        }
    }
}

app.config 修改使传输容量更大

<bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IService1" maxReceivedMessageSize="67108864" transferMode="Streamed"/>
            </basicHttpBinding>
        </bindings>
      

在这里插入图片描述

12.实验五:WCF和TCP的消息通信练习

  • App.config的配置
  <!-- Service Endpoints -->
        <!-- 参考修改endpoint ,注意 替换为自身的服务协议 命名控件.接口文件名-->
        <endpoint address="net.tcp://localhost:51888/Service1/" binding="netTcpBinding" contract="TestChatServer.IService1">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
  • 服务端
    接口:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace TestChatServer
{
    //需要服务端实现的协定
    [ServiceContract(Namespace = "TestChatServer",
        //SessionMode = SessionMode.Required,
        CallbackContract = typeof( IService1Callback))]
    public interface IService1
    {
        [OperationContract(IsOneWay = true)]
        void Login(string userName);

        [OperationContract(IsOneWay = true)]
        void Logout(string userName);

        [OperationContract(IsOneWay = true)]
        void Talk(string userName, string message);

        // TODO: 在此添加您的服务操作
    }

    //需要客户端实现的接口
    public interface IService1Callback
    {
        [OperationContract(IsOneWay = true)]
        void ShowLogin(string loginUserName);

        [OperationContract(IsOneWay = true)]
        void ShowLogout(string userName);
        [OperationContract(IsOneWay = true)]
        void ShowTalk(string userName, string message);

        [OperationContract(IsOneWay = true)]
        void Updateinfo(List<string> users,int usercount);
    }

        // 使用下面示例中说明的数据约定将复合类型添加到服务操作。
        // 可以将 XSD 文件添加到项目中。在生成项目后,可以通过命名空间“TestChatServer.ContractType”直接使用其中定义的数据类型。
        [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

构造User类和CC类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestChatServer
{
    class User
    {
        public string UserName { get; set; }
        public readonly IService1Callback callback;

        
        public User(string userName, IService1Callback callback)
        {
            this.UserName = userName;
            this.callback = callback;
        }
    
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestChatServer
{
    class CC
    {
        //保存连接的用户
        public static List<User> Users { get; set; }

        public static User GetUser(string userName)
        {
            User user = null;
            foreach (var v in Users)
            {
                if (v.UserName == userName)
                {
                    user = v;
                    return user;
                }
            }
            return user;
        }
    }
}

接口实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace TestChatServer
{
    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service1”。
    public class Service1 : IService1
    {
        public Service1()
        {
            if (CC.Users == null)
            {
                CC.Users = new List<User>();
            }
        }
        public void Login(string userName)
        {
            OperationContext context = OperationContext.Current;
            IService1Callback callback = context.GetCallbackChannel<IService1Callback>();
            User newUser = new User(userName, callback);
            CC.Users.Add(newUser);

            foreach (var user in CC.Users)
            {
                //发给每个线上的用户 
                user.callback.ShowLogin(userName);
            }
            SendInfoToAllUsers();
        }

        /// <summary>用户退出</summary>
        public void Logout(string userName)
        {
            User logoutUser = CC.GetUser(userName);
            foreach (var user in CC.Users)
            {
                //不需要发给退出用户
                if (user.UserName != logoutUser.UserName)
                {
                    user.callback.ShowLogout(userName);
                }
            }
            CC.Users.Remove(logoutUser);
            logoutUser = null; //将其设置为null后,WCF会自动关闭该客户端
            SendInfoToAllUsers();
        }

       
        public void Talk( string userName, string message)
        {
            foreach (var user in CC.Users)
            {
                //发给每个线上的用户 
                user.callback.ShowTalk(userName, message);
            }
        }


        // <summary>将当前在线情况发送给所有用户</summary>
        private void SendInfoToAllUsers()
        {
            int userCount = CC.Users.Count;
            List<string> users = new List<string>();
            foreach (var item in CC.Users)
            {
                string str = item.UserName;
                users.Add(str);
            }
            foreach (var user in CC.Users)
            {
                user.callback.Updateinfo(users, userCount);
            }
        }
    }
}

  • 客户端
    MainWindow 做主界面,新建 clientwindow 窗口作客户端
    在这里插入图片描述
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TestChatClient
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    ///  

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            StartWindow("西西", 580, 300);
            StartWindow("瓜瓜", 0, 0);
        }

        private void StartWindow(string userName, int left, int top)
        {
            ClientWindow w = new ClientWindow();
            w.Left = left;
            w.Top = top;
            w.UserName = userName;
            w.Owner = this;
            w.Closed += (sender, e) => this.Activate();
            w.Show();
        }

        private void btn2_Click(object sender, RoutedEventArgs e)
        {
            ClientWindow w = new ClientWindow();
            w.Owner = this;
            w.Closed += (sendObj, args) => this.Activate();
            w.Show();
        }
    }
}

在这里插入图片描述

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using TestChatClient.ServiceReference1;

namespace TestChatClient
{
    /// <summary>
    /// ClientWindow.xaml 的交互逻辑
    /// </summary>
    public partial class ClientWindow : Window,IService1Callback
    {
        public string UserName
        {
            get { return textBoxUserName.Text; }
            set { textBoxUserName.Text = value; }
        }
        private Service1Client client;
        public ClientWindow()
        {
            InitializeComponent();
            this.Closing += Window_Closing;
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            ChangeState(btnLogin, true, btnLogout, false);
            if (client != null)
            {
                client.Logout(UserName);
                client = null;
            }
        }
        private static void ChangeState(Button btnStart, bool isStart, Button btnStop, bool isStop)
        {
            btnStart.IsEnabled = isStart;
            btnStop.IsEnabled = isStop;
        }
        private void AddColorMessage(string str, SolidColorBrush color)
        {
            TextBlock t = new TextBlock();
            t.Text = str;
            t.Foreground = color;
            listBoxMessage.Items.Add(t);
        }

        //单击登录按钮引发的事件
        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {

            this.Cursor = Cursors.Wait;
            UserName = textBoxUserName.Text;
            InstanceContext context = new InstanceContext(this);
            client = new ServiceReference1.Service1Client(context);

            try
            {
                client.Login(textBoxUserName.Text);
                ChangeState(btnLogin, false, btnLogout, true);
            }
            catch (Exception ex)
            {
                MessageBox.Show("与服务端连接失败:" + ex.Message);
                return;
            }
            this.Cursor = Cursors.Arrow;

        }

        private void btnLogout_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
        //单击发送按钮引发的事件
        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            client.Talk( UserName, textBoxSend.Text);
            textBoxSend.Text = "";
        }

        //在对话文本框中按回车键时引发的事件
        private void textBoxTalk_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                client.Talk(UserName, textBoxSend.Text);
            }
            textBoxSend.Text = "";
        }

       
        #region 实现IService1Callback接口

        public void ShowLogin(string loginUserName)
        {
            AddColorMessage(string.Format("[{0}],进入群聊", loginUserName), Brushes.Black);
         
        }

        public void ShowLogout(string userName)
        {
            AddColorMessage(string.Format("[{0}],离开群聊", userName), Brushes.Black);
        }

        public void ShowTalk(string userName, string message)
        {
            AddColorMessage(string.Format("[{0}]说:{1}", userName, message), Brushes.Black);

        }

        public void Updateinfo(string[] users, int usercount)
        {
            listBoxUsers.Items.Clear();
            tb.Text = "在线人数:" + usercount;
            foreach (var item in users)
            {
                TextBlock t = new TextBlock();
                t.Text = item;
                Foreground = Brushes.Black;
                listBoxUsers.Items.Add(t);
            };

        }
            
        #endregion

      
    }
}

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值