wpf C# 数据库 c/s 个人信息管理 wpf局域网通信
系统功能基本要求
- 通讯录信息
-通讯人姓名
-联系方式
-工作地点
-城市
-备注 - 备忘录信息
-包括什么时间
-事件
-地点 - 日记信息
-时间
-地点
-事情
-人物
-个人财物管理
-总收入
-消费项目
-消费金额
-消费时间
-剩余资金
wpf局域网通信
wpf局域网聊天
想到做一个c/s,传输我就想到了json
json需要先安装nuget中Newtonsoft.Json;
安装
因为要找比较多,可以搜索
然后在文件写using Newtonsoft.Json;
把类转json
JsonConvert.SerializeObject(obj)
把json转类
private T Deserialize<T>(string str)
{
try
{
T temp = JsonConvert.DeserializeObject<T>(str);
return temp;
}
catch (JsonException e)
{
reminder = "输入不是ObservableCollection<T> json" + e.Message;
}
return default(T);
}
参考很多博客写出了局域网传输的代码
服务器:
public class principal_Computer
{
public principal_Computer(System.Action<string> ReceiveAction)
{
this.ReceiveAction = ReceiveAction;
ServerSocket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp);
IPAddress ip = IPAddress.Any;
ServerInfo = new IPEndPoint(ip , port);
ServerSocket.Bind(ServerInfo);//将SOCKET接口和IP端口绑定
ServerSocket.Listen(10);//开始监听,并且挂起数为10
ClientSocket = new Socket[65535];//为客户端提供连接个数
ClientNumb = 0;//数量从0开始统计
ServerThread = new Thread(new ThreadStart(RecieveAccept));//将接受客户端连接的方法委托给线程
ServerThread.Start();//线程开始运行
}
public void send(string str)
{
byte[] MsgBuffer = encoding.GetBytes(str);
for (int i = 0; i < ClientNumb; i++)
{
if (ClientSocket[i].Connected)
{
//回发数据到客户端
ClientSocket[i].Send(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None);
}
}
}
//接受客户端连接的方法
private void RecieveAccept()
{
while (true)
{
//Accept 以同步方式从侦听套接字的连接请求队列中提取第一个挂起的连接请求,然后创建并返回新的 Socket。
//在阻止模式中,Accept 将一直处于阻止状态,直到传入的连接尝试排入队列。连接被接受后,原来的 Socket 继续将传入的连接请求排入队列,直到您关闭它。
byte[] buffer = new byte[65535];
ClientSocket[ClientNumb] = ServerSocket.Accept();
ClientSocket[ClientNumb].BeginReceive(buffer , 0 , buffer.Length , SocketFlags.None ,
new AsyncCallback(RecieveCallBack) , ClientSocket[ClientNumb]);
ReceiveAction(encoding.GetString(buffer));
ClientNumb++;
}
}
//回发数据给客户端
private void RecieveCallBack(IAsyncResult AR)
{
try
{
Socket RSocket = (Socket)AR.AsyncState;
byte[] MsgBuffer = new byte[65535];
//同时接收客户端回发的数据,用于回发
RSocket.BeginReceive(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None , ar =>
{
try
{
RSocket.EndReceive(ar);
ReceiveAction(encoding.GetString(MsgBuffer).Trim('\0' , ' '));
RecieveCallBack(ar);
}
catch (SocketException e)
{
ReceiveAction("对方断开连接" + e.Message);
}
} , RSocket);
}
catch
{
}
}
private IPEndPoint ServerInfo;//存放服务器的IP和端口信息
private Socket ServerSocket;//服务端运行的SOCKET
private Thread ServerThread;//服务端运行的线程
private Socket[] ClientSocket;//为客户端建立的SOCKET连接
private int ClientNumb;//存放客户端数量
//private byte[] MsgBuffer;//存放消息数据
private int port = 54321; //端口号
private System.Action<string> ReceiveAction;
private Encoding encoding = Encoding.Default;
}
客户端
public class slaveComputer
{
public slaveComputer(System.Action<string> ReceiveAction)
{
this.ReceiveAction = ReceiveAction;
//定义一个IPV4,TCP模式的Socket
ClientSocket = new Socket(AddressFamily.InterNetwork , SocketType.Stream , ProtocolType.Tcp);
}
public void access(string ip)
{
ServerInfo = new IPEndPoint(IPAddress.Parse(ip) , port);
//客户端连接服务端指定IP端口,Sockket
ClientSocket.Connect(ServerInfo);
//将用户登录信息发送至服务器,由此可以让其他客户端获知
ClientSocket.Send(encoding.GetBytes(" 进入系统!\n"));
//开始从连接的Socket异步读取数据。接收来自服务器,其他客户端转发来的信息
//AsyncCallback引用在异步操作完成时调用的回调方法
ReceiveCallBack(ReceiveAction);
}
public void send(string str)
{
byte[] buffer = encoding.GetBytes(str);
ClientSocket.Send(buffer , 0 , buffer.Length , SocketFlags.None);
}
private IPEndPoint ServerInfo;
private Socket ClientSocket;
private Encoding encoding = Encoding.Default;
private System.Action<string> ReceiveAction;
private void ReceiveCallBack(System.Action<string> ReceiveAction)
{
try
{
//结束挂起的异步读取,返回接收到的字节数。 AR,它存储此异步操作的状态信息以及所有用户定义数据
byte[] MsgBuffer = new byte[65535];
ClientSocket.BeginReceive(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None , ar =>
{
//对方断开连接时, 这里抛出Socket Exception
//An existing connection was forcibly closed by the remote host
try
{
ClientSocket.EndReceive(ar);
ReceiveAction(encoding.GetString(MsgBuffer).Trim('\0' , ' '));
ReceiveCallBack(ReceiveAction);
}
catch (SocketException e)
{
ReceiveAction("对方断开连接" + e.Message);
}
} /*new AsyncCallback(ReceiveCallBack)*/ , null);
}
catch
{
}
}
private int port = 54321; //端口号
}
使用方法是
写出一个private System.Action<string> ReceiveAction;
初始化
ReceiveAction = str =>
{
//因为接受使用byte[] 会有很多空的字符,去掉就是消息
string temp= str.Trim('\0' , ' ');
if (!string.IsNullOrEmpty(temp))
{
//reminder是提示的字符串
reminder = temp;
}
};
使用服务器
var _principal_Computer = new principal_Computer(ReceiveAction);
使用客户端
var _slaveComputer = new slaveComputer(ReceiveAction);
_slaveComputer.access(ip);
客户端和服务器发送都是使用send
而服务器有多个客户端,发送可以指明发送到哪个客户端,可以全发送。
发送信息时,对信息进行一个类转json
因为发送信息不知道需要做什么,于是做了一个枚举,一个类
/// <summary>
/// 发送消息
/// </summary>
public class ctransmitter
{
public ctransmitter(int id , ecommand command , string str/*,int ran*/)
{
this.id = id.ToString();
this.command = command.ToString();
this.str = str;
//this.ran = ran.ToString();
}
public string id
{
set;
get;
}
public string command
{
set;
get;
}
public string str
{
set;
get;
}
//public string ran
//{
// set;
// get;
//}
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
public enum ecommand
{
login,//登录
id,//分配id
faddressBook,//通讯录
ce
}
ctransmitter里面ToString把这个类转换为json,之后接收就把json转换为类,然后根据command来得到发送的命令
ctransmitter transmitter = JsonConvert.DeserializeObject<ctransmitter>(json);
ecommand command = (ecommand)Enum.Parse(typeof(ecommand) , transmitter.command);
switch (command)
{
case ecommand.ce:
reminder("收到" + transmitter.id);
break;
}
客户端循环等待服务器发送的消息,收到就把信息放到一个byte[]如果byte大小不够,分为多次。
服务器把信息发送可以依靠客户端所在的id或全部发。
所有数据转换为Default
private Encoding encoding = Encoding.Default;
ClientSocket[i]存放不如使用list来存放,因为这个长度固定,在很多机器连接断开就没了,不过这个是简单的,所以用了ClientSocket[i]
端口号都被写成没法修改,这个可以放在view一个textbox来修改
生成addressBook界面
先做一个ViewModel
viewaddressBook.cs
因为需要访问_model,在构造传入viewModel初始的_model
public viewaddressBook(model.model _model)
{
this._model = _model;
}
WPF跨线程访问线程安全的数据(如解决:该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection)
更新数据中途出现了该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection
查到了使用invoke就可以
从输入一个string然后更新
private void newaddressBook(string str)
{
try
{
ObservableCollection<caddressBook> temp = DeserializeObject<caddressBook>(str);
System.Windows.Application.Current.Dispatcher.Invoke
(() =>
{
addressbook.Clear();
foreach (var t in temp)
{
addressbook.Add(t);
}
});
}
catch (JsonException e)
{
reminder = "输入不是ObservableCollection<caddressBook> json" + e.Message;
}
}
读取信息null
在运行返回一个错误
null
查询了是读取有一个null
const string id = "id";
const string MTIME = "MTIME";
const string PLACE = "PLACE";
const string INCIDENT = "INCIDENT";
const string CONTACTSID = "NAME";
using (SqlConnection sql = new SqlConnection(connect))
{
sql.Open();
using (SqlCommand cmd = new SqlCommand(strsql , sql))
{
using (SqlDataReader read = cmd.ExecuteReader())
{
if (!read.HasRows)
return diary;
int idindex = read.GetOrdinal(id);
int MTIMEindex = read.GetOrdinal(MTIME);
int PLACEindex = read.GetOrdinal(PLACE);
int INCIDENTindex = read.GetOrdinal(INCIDENT);
int CONTACTSIDindex = read.GetOrdinal(CONTACTSID);
while (read.Read())
{
diary.Add(new cdiary()
{
id = read.GetInt32(idindex).ToString() ,
MTIME = read.GetDateTime(MTIMEindex).ToString() ,
PLACE = read.GetString(PLACEindex) ,
incident = read.GetString(INCIDENTindex) ,
CONTACTSID = read.GetString(CONTACTSIDindex)
});
}
}
}
}
里面有些是null
使用
PLACE = read[PLACEindex] as string;
就可以
出现了把PLACE.Trim();错误可以使用
private string DBNullstring<T>(object obj)
{
try
{
return obj == System.DBNull.Value ? " " : ( (T)obj ).ToString();
}
catch
{
return string.Empty;
}
}
读取发来数据需要时间
byte[] MsgBuffer = new byte[65535];
ClientSocket.BeginReceive(MsgBuffer , 0 , MsgBuffer.Length , SocketFlags.None , ar =>
{
//对方断开连接时, 这里抛出Socket Exception
//An existing connection was forcibly closed by the remote host
try
{
ClientSocket.EndReceive(ar);
ReceiveAction(encoding.GetString(MsgBuffer).Trim('\0' , ' '));
ReceiveCallBack(ReceiveAction);
}
catch (SocketException e)
{
reminder("对方断开连接" + e.Message);
}
catch(ObjectDisposedException e)
{
reminder (id.ToString() + "连接退出" + e.Message);
return;
}
MsgBuffer比发来信息小,那么分为多次,而在识别json会出现把字符串弄成多个,这样就出现json错误
需要在发送使用分开或使用大的buffer
连接数据库
连接数据库
$"Data Source={DataSource};Initial Catalog={InitialCatalog};Integrated Security=True";
DataSource 数据库ip
InitialCatalog 数据库名
strsql是sql语句
using (SqlConnection sql = new SqlConnection(connect))
{
sql.Open();
using (SqlCommand cmd = new SqlCommand(strsql , sql))
{
using (SqlDataReader read = cmd.ExecuteReader())
{
try
{
if (!read.HasRows)
return null;
//读数据
}
catch
{
}
}
}
}
数据库获得数据
从数据库获得数据可以使用SqlDataReader read = cmd.ExecuteReader()
读取read的内容
连接
const string addressBookname = "vaddressbook";
string sqlAddressBook = $"{usesql}{line}SELECT * FROM {addressBookname};";
使用read[str]可以获得所在数据,
const string id = "id";
const string name = "name";
const string contact = "contact";
const string caddress = "caddress";
const string city = "city";
const string comment = "comment";
获得字符串所在
int idindex = read.GetOrdinal(id);
int nameindex = read.GetOrdinal(name);
int contactindex = read.GetOrdinal(contact);
int caddressindex = read.GetOrdinal(caddress);
int cityindex = read.GetOrdinal(city);
int commentindex = read.GetOrdinal(comment);
caddressBook temp = new caddressBook
{
id = read.GetInt32(idindex).ToString() ,
name = read.GetString(nameindex).Trim() ,
contact = read.GetString(contactindex).Trim() ,
address = read.GetString(caddressindex).Trim() ,
city = read.GetString(cityindex).Trim() ,
comment = read.GetString(commentindex).Trim()
};
这种 方法使用比较难,因为需要写很多字符串和int。
对string可以直接str=read[str] as string;
发送数据
public void send(string str)
{
if (ClientSocket.Connected)
{
byte[] buffer = encoding.GetBytes(str);
ClientSocket.Send(buffer , 0 , buffer.Length , SocketFlags.None);
}
else
{
try
{
access(ip);
}
catch(SocketException e)
{
reminder ("连接失败 " + e.Message);
}
catch(InvalidOperationException e)
{
reminder("服务器没有开启"+e.Message);
}
}
}
客户端可以设置ip
<TextBlock Text="ip" />
<TextBox Text="{Binding Path=_model.ip,Mode=TwoWay}" Width="100"/>
<Button Content="确定" Click="确定"/>
添加通讯
public void add()
{
if (accord())
{
foreach (var t in laddressBook)
{
if (addressbook_equals(addressBook, t))
{
warn = "信息重复";
return;
}
}
_model.send(ecommand.addaddressBook , addressBook.ToString());
reminder = "添加通讯";
addressBook = new caddressBook();
}
}
查询可以没有输入为*
删除,判断有没修改,如果没有发送删除的类
if (addressBook.Equals(_item))
{
_model.send(ecommand.daddressBook , _item.ToString());
reminder = "删除通讯";
}
通讯录 日记都一样,只是改了名字和一些,日记需要时间,所以判断是否存在时间,如果有,格式是否正确。
程序难在写了好多次不同的数据,这些可以合并为一个,然后修改,看到通讯录重复,没有去把重复的作为一个类,每个都写一次,如果要修改,经常出错,git可以撤销
git reset --hard id
wpf C# 数据库 c/s 个人信息管理 wpf局域网通信的更多相关文章
- WPF老矣,尚能饭否——且说说WPF今生未来(下):安心
在前面的上.中篇中,我们已经可以看到园子里朋友的点评“后山见! WPF就比winform好! 激情对决”.看到大家热情洋溢的点评,做技术的我也很受感动.老实说,如何在本文收笔--WPF系列文章,我很紧 ...
- WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...
- “WPF老矣,尚能饭否”—且说说WPF今生未来(上):担心
近日微软公布了最新的WPF路线图,一片热议:对于老牌控件提供商葡萄城来说,这是WPF系列控件一个重要的机遇,因此,Spread Studio for WPF产品做了一次重要更新,并随着Spread S ...
- WPF老矣,尚能饭否——且说说WPF今生未来(中):策略
本文接上文<WPF老矣,尚能饭否——且说说WPF今生未来(上):担心>继续. “上篇”中部分精彩的点评: 虽然WPF不再更新了,但是基于WPF的技术还是在发展着,就比如现在的WinRT,只 ...
- [WPF系列]基础学习(一) WPF是什么?
引言 学习之前,我们首先大概了解下WPF诞生的背景以及它所能解决的问题或者新颖之处.WPF作为微软新一代的用户界面技术, WPF简介 WPF的全称是WindowsPresentationFound ...
- WPF快速入门系列(5)——深入解析WPF命令
一.引言 WPF命令相对来说是一个崭新的概念,因为命令对于之前的WinForm根本没有实现这个概念,但是这并不影响我们学习WPF命令,因为设计模式中有命令模式,关于命令模式可以参考我设计模式的博文:h ...
- WPF快速入门系列(4)——深入解析WPF绑定
一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...
- wpfのuri(让你完全明白wpf的图片加载方式以及URI写法)
绝对 pack WPF URI pack://application:,,,/是协议:“,,,”是“///”的变体 1.资源文件 — 本地程序集 Uri uri = new Uri("pac ...
- WPF笔记(1.10 绘图)——Hello,WPF!
原文:WPF笔记(1.10 绘图)--Hello,WPF! 书中的代码语法过时了,改写为以下(测试通过): <Button> <Button.L ...
随机推荐
- 团队作业——Alpha冲刺之事后诸葛亮
小组成员: 武健男:201421123091 林俊鹏:201421123076 何跃斌:201421123082 陈鑫龙:201421123078 潘益靖:201421123086 黄睿:201421 ...
- 201521123109《java程序设计》第五周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 2. 书面作业 作业参考文件下载 1.代码阅读:Child压缩包内源代码 1.1 ...
- 201521123104 《JAVA程序设计》第二周学习总结
1. 本周学习总结 认识了JAVA编程中一些类型与变量,了解了一些基本运算符的使用 变量在命名时,不可以使用数字或一些特殊字符作为开头 不可以声明局部变量后未指定任何值给它之前就使用变量 在程序中写下 ...
- 201521123029《Java程序设计》第十三周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1.网络基础 1.1 比较ping www.baidu.com与ping cec.jmu. ...
- Day-14: 常用的内建模块
collections包含对tuple.list.dict等派生出新功能 namedtuple用来为tuple类型派生出一个新名字的tuple类,并提供用属性引出的功能. >>> f ...
- Python跨目录调用模块
目的就是将脚本执行的根目录加入环境变量. #!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = '人生入戏' import os,sy ...
- NameError: name 'messagebox' is not defined 错误处理
写了段代码,想在按下button的时候跳个提示框出来,调试的时候提示了messagebox未定义 from tkinter import * def test_show(): messagebox.s ...
- Postman高级应用——流程控制、调试、公共函数、外部数据文件
postman客户端下载地址:https://www.getpostman.com/apps 目录 流程控制 调试 公共函数 外部数据文件 流程控制 流程控制简言之就是设置接口的执行顺序,流程控制只有 ...
- Invoke 用法
转自:http://blog.sina.com.cn/s/blog_5a6f39cf0100s23x.html 在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法 ...
- 翻译连载 | 第 10 章:异步的函数式(上)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...