简介:
本文将介绍简单、复杂的卡顿问题(本文的复杂卡顿问题,表现在UI不能更新)。
一、简单卡顿问题及其解决方法,请参考我的另一篇博文
C#.网络编程 Socket基础(四) WPF系统Socket TCP协议 服务器与客户端 不同类型文件传输,解决UI线程(异步委托)与工作线程的卡顿问题
设计思路 主线程——>实例化——>次线程——>在次线程中,直接用实例更新到主线线程的UI 如图所示。
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.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;
using Microsoft.Win32;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Threading;
using KeenRayLargePC.Views;
using KeenRayLargePC.PublicFunc;
namespace KeenRayLargePC
{
public partial class MainWindow : Window
{
//传递页面类型
string strPageType = null;
//启动页面标志
static byte[] byt_StudyPage_RecFlag = new byte[2] { 0x00, 0 };
static byte[] byt_ReviewPage_RecFlag = new byte[2] { 0x01, 0 };
static byte[] byt_HistoryPage_RecFlag = new byte[2] { 0x02, 0 };
//启动图片接收、字符接收标志
static byte[] byt_String_RecFlag = new byte[2] { 0x00, 0 };
static byte[] byt_Image_RecFlag = new byte[2] { 0x04, 0 };
//启动用户、列表、曝光标志
static byte[] byt_User_RecFlag = new byte[2] { 0x00, 0 };//这里出现的0x00标志与前面的0x00没有联系。
static byte[] byt_ListView_RecFlag = new byte[2] { 0x08, 0 };
static byte[] byt_Expose_RecFlag = new byte[2] { 0x10, 0 };
//启动KV、mA、ms、mAs标志
static byte[] byt_ExposeKV_RecFlag = new byte[2] { 0x00, 0 };
static byte[] byt_ExposemA_RecFlag = new byte[2] { 0x20, 0 };
static byte[] byt_Exposems_RecFlag = new byte[2] { 0x40, 0 };
static byte[] byt_ExposemAs_RecFlag = new byte[2] { 0x60, 0 };
//启动 Plus/Reduce标志
static byte[] byt_ExposePlus_RecFlag = new byte[2] { 0x00, 0 };
static byte[] byt_ExposeReduce_RecFlag = new byte[2] { 0x80, 0 };
Int16 Int16_StudyPage_RecFlag = System.BitConverter.ToInt16(byt_StudyPage_RecFlag, 0);
Int16 Int16_ReviewPage_RecFlag = System.BitConverter.ToInt16(byt_ReviewPage_RecFlag, 0);
Int16 Int16_HistoryPage_RecFlag = System.BitConverter.ToInt16(byt_HistoryPage_RecFlag, 0);
Int16 Int16_String_RecFlag = System.BitConverter.ToInt16(byt_String_RecFlag, 0);
Int16 Int16_Image_RecFlag = System.BitConverter.ToInt16(byt_Image_RecFlag, 0);
Int16 Int16_User_RecFlag = System.BitConverter.ToInt16(byt_User_RecFlag, 0);
Int16 Int16_ListView_RecFlag = System.BitConverter.ToInt16(byt_ListView_RecFlag, 0);
Int16 Int16_Expose_RecFlag = System.BitConverter.ToInt16(byt_Expose_RecFlag, 0);
Int16 Int16_ExposeKV_RecFlag = System.BitConverter.ToInt16(byt_ExposeKV_RecFlag, 0);
Int16 Int16_ExposemA_RecFlag = System.BitConverter.ToInt16(byt_ExposemA_RecFlag, 0);
Int16 Int16_Exposems_RecFlag = System.BitConverter.ToInt16(byt_Exposems_RecFlag, 0);
Int16 Int16_ExposemAs_RecFlag = System.BitConverter.ToInt16(byt_ExposemAs_RecFlag, 0);
Int16 Int16_ExposePlus_RecFlag = System.BitConverter.ToInt16(byt_ExposePlus_RecFlag, 0);
Int16 Int16_ExposeReduce_RecFlag = System.BitConverter.ToInt16(byt_ExposeReduce_RecFlag, 0);
Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
StudyPage studyPage = new StudyPage();
ReviewPage reviewPage = new ReviewPage();
HistoryPage historyPage = new HistoryPage();
ExposeValueMsgFunc exposeValueMsgFunc = new ExposeValueMsgFunc();
ImageFunc imageFunc = new ImageFunc();
ListViewMsgFunc listViewMsgFunc = new ListViewMsgFunc();
UserMsgFunc userMsgFunc = new UserMsgFunc();
public MainWindow()
{
InitializeComponent();
IPAddress serverIP = IPAddress.Parse("127.0.0.1");
IPEndPoint serverIPEndPoint = new IPEndPoint(serverIP, 50000);
//获得要连接的远程服务器应用程序的IP地址和端口号
Client.Connect(serverIPEndPoint);
int i1 = Thread.CurrentThread.ManagedThreadId;
//MessageBox.Show(Thread.CurrentThread.ManagedThreadId);
//ShowMsg(Thread.CurrentThread.ManagedThreadId);
//MessageBox.Show("连接成功1");
//开启一个新的线程不停地接收服务器端发来的消息
Thread threadReceive = new Thread(Receive);
//将threadReceive设置为后台线程
threadReceive.IsBackground = true;
//启动线程
threadReceive.Start();
}
void Receive()
{
int i2 = Thread.CurrentThread.ManagedThreadId;
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 3];
//实际接收到的有效字节数
int r = 0;
r = Client.Receive(buffer);
if (r == 0)//未收到任何东西
{
MessageBox.Show("中止1");
break;
}
else//有收到信息
{
int i3 = Thread.CurrentThread.ManagedThreadId;
//拷贝,找出butter的标志位。
byte[] byt_RecFlag = new byte[2];
Array.ConstrainedCopy(buffer, 0, byt_RecFlag, 0, byt_RecFlag.Length);
//转成整数,以便进行与操作。
Int16 Int16_byt_RecFlag = System.BitConverter.ToInt16(byt_RecFlag, 0);
//Int16_byt_RecFlag & 0x03,表示提取字节的前两位。
if ((Int16_byt_RecFlag & 0x03) == Int16_StudyPage_RecFlag)//前两位为0,则启动StudyPage。
{
int i4 = Thread.CurrentThread.ManagedThreadId;
strPageType = "studyPage";
App.Current.Dispatcher.Invoke((Action)delegate ()
{
int i5 = Thread.CurrentThread.ManagedThreadId;
Frame.Content = studyPage;
});
//Int16_byt_RecFlag & 0x04,表示提取字节的第三位。
if ((Int16_byt_RecFlag & 0x04) == Int16_String_RecFlag)//启动文字信息。
{
if ((Int16_byt_RecFlag & 0x11) == Int16_User_RecFlag)//启动用户信息
{
//this.Dispatcher.BeginInvoke((Action)delegate ()//次线程threadReceive调用了主线程 App.Current.
//userMsgFunc.GetUserMsgFunc(r, buffer, strPageType);
//App.Current.Dispatcher.BeginInvoke((Action)delegate ()
//{
// int i6 = Thread.CurrentThread.ManagedThreadId;//主线程
userMsgFunc.GetUserMsgFunc(r, buffer, studyPage);
//});
//标志位占两个字节
//int iFlagByteLong = 2;
字符信息的长度占一个字节
//int iMsgByteLong = 1;
病人信息的字节长度
//int iPatientNumByteLong = 10;
//int PatientNameByteLong = 12;
//int iPatientSexByteLong = 3;
//int iPatientAgeByteLong = 3;
//int iPatientBodyByteLong = 6;
用户信息
//byte[] byt_PatientNum = new byte[iPatientNumByteLong];
//byte[] byt_PatientnName = new byte[PatientNameByteLong];
//byte[] byt_PatientSex = new byte[iPatientSexByteLong];
//byte[] byt_PatientAge = new byte[iPatientAgeByteLong];
//byte[] byt_PatientBody = new byte[iPatientBodyByteLong];
//string str_PatientNum = null;
//string str_PatientnName = null;
//string str_PatientSex = null;
//string str_PatientAge = null;
//string str_PatientBody = null;
将byt_bufferVar的用户内容按固定字节拷贝出来
//Array.ConstrainedCopy(buffer, (iFlagByteLong + iMsgByteLong), byt_PatientNum, 0, iPatientNumByteLong);//byt_bufferVar的第四个字节(包含第四个字节)之后才是字符内容。
//Array.ConstrainedCopy(buffer, (iFlagByteLong + iMsgByteLong + iPatientNumByteLong), byt_PatientnName, 0, PatientNameByteLong);
//Array.ConstrainedCopy(buffer, (iFlagByteLong + iMsgByteLong + iPatientNumByteLong + PatientNameByteLong), byt_PatientSex, 0, iPatientSexByteLong);
//Array.ConstrainedCopy(buffer, (iFlagByteLong + iMsgByteLong + iPatientNumByteLong + PatientNameByteLong + iPatientSexByteLong), byt_PatientAge, 0, iPatientAgeByteLong);
//Array.ConstrainedCopy(buffer, (iFlagByteLong + iMsgByteLong + iPatientNumByteLong + PatientNameByteLong + iPatientSexByteLong + iPatientAgeByteLong), byt_PatientBody, 0, iPatientBodyByteLong);
包含了\0的字符串
//str_PatientNum = System.Text.Encoding.UTF8.GetString(byt_PatientNum);
//str_PatientnName = System.Text.Encoding.UTF8.GetString(byt_PatientnName);
//str_PatientSex = System.Text.Encoding.UTF8.GetString(byt_PatientSex);
//str_PatientAge = System.Text.Encoding.UTF8.GetString(byt_PatientAge);
//str_PatientBody = System.Text.Encoding.UTF8.GetString(byt_PatientBody);
去掉\0的字符串
//str_PatientNum = str_PatientNum.Replace("\0", "");
//str_PatientnName = str_PatientnName.Replace("\0", "");
//str_PatientSex = str_PatientSex.Replace("\0", "");
//str_PatientAge = str_PatientAge.Replace("\0", "");
//str_PatientBody = str_PatientBody.Replace("\0", "");
将用户字符串信息,更新到UI。
//App.Current.Dispatcher.BeginInvoke((Action)delegate ()//MainWindow ID
//{
// int i8 = Thread.CurrentThread.ManagedThreadId;
// if (strPageType == "studyPage")
// {
// int i9 = Thread.CurrentThread.ManagedThreadId;
// //StudyPage studyPage = new StudyPage();
// studyPage.lbl_PatientNum_Study.Content = str_PatientNum;
// studyPage.lbl_PatientnName_Study.Content = str_PatientnName;
// studyPage.lbl_PatientSex_Study.Content = str_PatientSex;
// studyPage.lbl_PatientAge_Study.Content = str_PatientAge;
// studyPage.lbl_PatientBody_Study.Content = str_PatientBody;
// }
// else if (strPageType == "reviewPage")
// {
// //ReviewPage reviewPage = new ReviewPage();
// reviewPage.lbl_PatientNum_Review.Content = str_PatientNum;
// reviewPage.lbl_PatientnName_Review.Content = str_PatientnName;
// reviewPage.lbl_PatientSex_Review.Content = str_PatientSex;
// reviewPage.lbl_PatientAge_Review.Content = str_PatientAge;
// reviewPage.lbl_PatientBody_Review.Content = str_PatientBody;
// }
//});
}
else if ((Int16_byt_RecFlag & 0x11) == Int16_ListView_RecFlag)//启动列表信息
{
listViewMsgFunc.GetListViewMsgFunc(r, buffer, strPageType);
}
else if ((Int16_byt_RecFlag & 0x11) == Int16_Expose_RecFlag)//启动曝光信息
{
if ((Int16_byt_RecFlag & 0x60) == Int16_ExposeKV_RecFlag)//启动KV
{
if ((Int16_byt_RecFlag & 0x80) == Int16_ExposePlus_RecFlag)//加
{
string strVar = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_KVValue.Content = strVar;
});
}
else if ((Int16_byt_RecFlag & 0x80) == Int16_ExposeReduce_RecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_KVValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
});
}
}
else if ((Int16_byt_RecFlag & 0x60) == Int16_ExposemA_RecFlag)//启动mA
{
if ((Int16_byt_RecFlag & 0x80) == Int16_ExposePlus_RecFlag)//加
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_mAValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
});
}
else if ((Int16_byt_RecFlag & 0x80) == Int16_ExposeReduce_RecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_mAValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
});
}
}
else if ((Int16_byt_RecFlag & 0x60) == Int16_Exposems_RecFlag)//启动ms
{
if ((Int16_byt_RecFlag & 0x80) == Int16_ExposePlus_RecFlag)//加
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_msValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
});
}
else if ((Int16_byt_RecFlag & 0x80) == Int16_ExposeReduce_RecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_msValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
});
}
}
else if ((Int16_byt_RecFlag & 0x60) == Int16_ExposemAs_RecFlag)//启动mAs
{
if ((Int16_byt_RecFlag & 0x80) == Int16_ExposePlus_RecFlag)//加
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_mAsValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
});
}
else if ((Int16_byt_RecFlag & 0x80) == Int16_ExposeReduce_RecFlag)//减
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
studyPage.lbl_mAsValue.Content = exposeValueMsgFunc.GetExposeValueMsgFunc(r, buffer);
});
}
}
}
}
else if ((Int16_byt_RecFlag & 0x04) == Int16_Image_RecFlag)//启动图片信息
{
App.Current.Dispatcher.Invoke((Action)delegate ()
{
imageFunc.GetImageFunc(r, buffer, strPageType);
});
}
}
else if ((Int16_byt_RecFlag & 0x03) == Int16_ReviewPage_RecFlag)//前两位为1,则启动ReviewPage
{
strPageType = "reviewPage";
App.Current.Dispatcher.Invoke((Action)delegate ()
{
Frame.Content = reviewPage;
});
//Frame.Content = reviewPage;
//Int16_byt_RecFlag & 0x04,表示提取字节的第三位。
if ((Int16_byt_RecFlag & 0x04) == Int16_String_RecFlag)//启动文字-用户信息。
{
userMsgFunc.GetUserMsgFunc(r, buffer, studyPage);
//App.Current.Dispatcher.Invoke((Action)delegate ()
//{
// //Frame.Content = reviewPage;
// userMsgFunc.GetUserMsgFunc(r, buffer, strPageType);
//});
}
else if ((Int16_byt_RecFlag & 0x04) == Int16_Image_RecFlag)//启动图片信息
{
imageFunc.GetImageFunc(r, buffer, strPageType);
}
}
else if ((Int16_byt_RecFlag & 0x03) == Int16_HistoryPage_RecFlag)//前两位为2,则启动HistoryPage
{
strPageType = "HistoryPage";
App.Current.Dispatcher.Invoke((Action)delegate ()
{
Frame.Content = historyPage;
});
//Int16_byt_RecFlag & 0x04,表示提取字节的第三位。
if ((Int16_byt_RecFlag & 0x04) == Int16_String_RecFlag)//启动文字信息。
{
if ((Int16_byt_RecFlag & 0x11) == Int16_ListView_RecFlag)//启动列表信息
{
listViewMsgFunc.GetListViewMsgFunc(r, buffer, strPageType);
}
}
}
}
}
catch
{
int iShowMessageBoxCount = 0;
while (iShowMessageBoxCount < 1)
{
MessageBox.Show("连接不上");
iShowMessageBoxCount++;
}
//MessageBox.Show("重新启动连接");
//MessageBox.Show("连接不上");
//break;
}
}
}
void ShowMsg(string str)
{
studyPage.txtLog.AppendText(str + "\r\n");
}
private void BtnSysShutDown_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
}
二、复杂的卡顿问题
2.1、复杂卡顿问题的入门介绍
关于Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析,这里有一篇典型的博客:
https://blog.csdn.net/yl2isoft/article/details/11711833
2.2、 App.Current.Dispatcher.Invoke 和 this.Dispatcher.BeginInvoke的区别
两者都是指当前的窗口
2.3、我所遇到的复杂卡顿问题及其解决办法(恍然大悟)。
问题:
在我的WPF工程里面,Sokcets介绍一切正常,数据介绍没有问题,单步执行没有没有,而且采用了之前的简单卡顿的解决方案来设计程序。次线性接收信息,经过一番处理后,但就是没办法更新到主线程MainWindow中:
原来,问题出现在一番处理的过程中。我的设计思路 是设计思路 主线程——>studyPage实例化——>次线程——>studyPage实例化——>在次线程中,直接用实例更新到主线线程的UI 如图所示。
第二个studyPage实例化,我是放到另外一个类中:
非常糟糕的是,多了这一步实例化,让我陷入了万劫不复的地步。其导致UI不能更新。
为了分析其根本原因,我现在把第一次实例化studyPage的数据拿出来:
第二次实例化后的数据:
看到了没有,这个一个局部变量,当类UserMsgFunc消亡后,类内的实例化studyPage也跟着消亡。所以第二个实例化的数据studyPage,与第一个studyPage的数据根本没有半毛钱关系。第一个studyPage的数据还是保持原样,至始至终,第二次的实例化数据从来没有更新到主线程MianWindow的UI上。
以上问题,属于把数据传到父类的问题。关于把数据传递父类的方法,有几种方法:
方法1:
将第一个studyPage,作为一个参数,传递给类UserMsgFunc即可。即始终保持建立一个实例化的原则。
方法2:设置静态类static即可
具体参考 C# 基础(六)C# WPF中全面理解 全局变量、局部变量的区别与实现
方法3:回调函数
方法4:委托。