目录
四、WPF(windows presentation foundation)
一、前言
无奈上位机设计要从QT转战Microsoft,所以不得不学习一下CSharp的套路了。C# 是微软推出的一门面向对象的通用型编程语言,它除了可以开发 PC 软件、网站(借助 ASP.NET)和 APP(基于 Windows Phone),还能作为游戏脚本,编写游戏逻辑。
C#基本语法
C#函数调用
C#窗体应用程序设计
C#高级界面设计
Cshape特点
1.简单、安全:不再使用指针,不允许直接读取内存等不安全的操作,c#中会自动管理内存,不需要程序员手动分配和释放,这样可以有效避免内存泄露。
2.面向对象语言的特征:封装、继承、多态
C#与.net
.net是一个开发平台,而C#是一种在.net开发平台上使用的编程语言。.NET支持VB.NET,Python, J#,C++.NET等,最多的还是C#语言。
.NET Framework:可以快速开发、部署网站服务及应用程序的开发平台,是window一个组件,包括CLR虚拟执行系统和.NET Framework类库。
CLR 是 .NET Framework 的基础。用户可以将 CLR 看作一个在执行时管理代码的代码,它提供内存管理、线程管理和远程处理等核心服务,并且还强制实施严格类型安全以及可提高安全性和可靠性的管理
.NET Framework体系结构:
注意:在visual studio中解决方案名称不一定与项目名称相同,在同一个解决方案中允许设置多个项目。那么一个解决方案下如何引用其他项目:
1.选择调用其他项目资源的项目->“引用”->右击“添加引用”->“项目”->选择要调用的项目
2.在该项目下的资源中添加“using 被调用的资源名称;”
3.实例化被调用的资源,为该项目使用
二、C#语言
2.1 基本数据类型
sbyte,byte,short, ushort, int,uint, long, ulongfloat,double,\r回车,\n换行,bool
/// 可以描述方法的内容
decimal 类似float浮点型,但是没有精度损耗
null 空类型,只有string可以为null
2.2 基本运算
/除法,%取余等, 逻辑运算: !=
x??y 如果x为null,则结果为y,否则结果为x
2.3 变量
变量可以理解为存放数据的容器,并且在将值存放到变量中时还要为变量指定数据类型
变量与常量相对: const double PI = 3.14;
2.4特性
封装封装类、接口、方法;继承:类之间复用;多态:类的继承或接口实现
2.5类
类声明语法:
类的访问修饰符 修饰符 类名
{
类的成员
}
类的划分:非静态类和静态类
非静态类使用的关键字new实例化对象,一个类可以实例化多个对象。
类 对象名 = new 类();
静态类:在静态类中只能有静态成员,不能有实例成员;静态类不能创建对象,不能new对象
public static class MyStaticClass
{
public static string Name { get; set; }
public static void SayHi()
{
Console.WriteLine("hi");
}
}
C#构造函数:实例构造函数,静态构造函数,私有构造函数
静态构造函数:在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数以初始化类;这在实例化类之前要做一些事情很有用。
私有构造函数:是一种特殊的实例构造函数。 它通常用于只包含静态成员的类中。 如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例。声明空构造函数可阻止自动生成默认构造函数。 请注意,如果不对构造函数使用访问修饰符,则在默认情况下它仍为私有构造函数。 但是,通常会显式地使用 private 修饰符来清楚地表明该类不能被实例化
- 类的访问修饰符:用于设定对类的访问限制,包括 public、internal 或者不写,用 internal 或者不写时代表只能在当前项目中访问类;public 则代表可以在任何项目中访问类。
- 修饰符:修饰符是对类本身特点的描述,包括 abstract、sealed 和 static。abstract 是抽象的意思,使用它修饰符的类不能被实例化;sealed 修饰的类是密封类,不能 被继承;static 修饰的类是静态类,不能被实例化。
- 类名:类名用于描述类的功能,因此在定义类名时最好是具有实际意义,这样方便用户理解类中描述的内容。在同一个命名空间下类名必须是唯一的。
- 类的成员:在类中能定义的元素,主要包括字段、属性、方法
类中的成员包括字段、属性、方法。每个类成员在定义时需要指定访问修饰符、修饰符:public,private, internal,protected,readdonly(只读),static(静态的)。定义字段的语法形式: 访问修饰符 修饰符 数据类型 字段名;
namespace code_1
{
class Test
{
private int id; //定义私有的整型字段 id
public readonly string name; //定义公有的只读字符串类型字段 name
internal static int age; //定义内部的静态的整型字段 age
private const string major = "计算机"; //定义私有的字符串类型常量 major
}
}
类方法定义:
访问修饰符 返回值类型 方法名(参数列表)
{
语句块;
}
属性常用的书写方法:
public int age{get; set;}//get说明可以获取属性的值,set说明可以设置属性的值
修饰符:virtual虚拟的, abstract抽象的,override(重写的,类继承可使用),static(静态的),sealed(密封的)
#region 指令:是一个分块预处理命令,它主要用于编辑代码的分段,在编译时会被自动删除。#region块必须以#endregion指令终止。#region块不能与#if块重叠。但是,可以将#region块嵌套在#if块内,或将#if块嵌套在#region块内。
函数传参参数修饰符:
- 无修饰符传参:按值拷贝传递
- out传参:输出参数由北调用的方法复制,按引用传递(强制对该参数操作)
- ref传参: 调用者赋初值,并且可以被调用的方法重新赋值,按引用传递(可选的对其操作)
2.6 枚举变量定义
将枚举值和显示值绑定在一起
public enum Level
{
//Bad
[Description("Bad")]
B = -1,
//Normal
[Description("Normal")]
N = 0,
//Good
[Description("Good")]
G = 1,
//Very Good
[Description("Very Good")]
VG = 2
}
2.7 定义数组
//一维数组语法: 类型[] 数组名 = new 数组类型[]{初始值};
int[] array = new int[]{1,2,3,4,5,6};//不定长数组
int[] array = new int[3]{1,2,3};//定长数组
string[] names = new string[3] {"Matt", "Joanne", "Robert"};
//多维数组语法: 类型[,] 数组名 = new 数组类型[,]{{初始值},{初始值}};
int[,] numbers = new int[,]{{1,2,3},{1,2,3}}; //不定长
int[,] numbers = new int[2,2]{{1,2},{1,2}}; //定长
string[,] names = new string[5,4];
//如果提供了初始值设定项,则还可以省略 new 运算符
string[] mf3={"c","c++","c#"};
int[] numbers = {1, 2, 3, 4, 5};
//PadLeft 实现左边补足,就是检查字符串长度是否超过10,不超过的左侧加0补足到10的长度
String.PadLeft(10,'0');
//PadRight 实现右边补足,就是检查字符串长度是否超过10,不超过的右侧加0补足到10的长度
String.PadRight (10,'0');
//list数组
List<CANMsg>[] aryList= new List<CANMsg>[6];//此处只是声明了该list
//初始化
for (int i=0;i<6;i++)
aryList = new List<CANMsg>();
2.8 预处理指令
预处理器指令 | 描述 |
---|---|
#define | 它用于定义一系列成为符号的字符。 |
#undef | 它用于取消定义符号。 |
#if | 它用于测试符号是否为真。 |
#else | 它用于创建复合条件指令,与 #if 一起使用。 |
#elif | 它用于创建复合条件指令。 |
#endif | 指定一个条件指令的结束。 |
#line | 它可以让您修改编译器的行数以及(可选地)输出错误和警告的文件名。 |
#error | 它允许从代码的指定位置生成一个错误。 |
#warning | 它允许从代码的指定位置生成一级警告。 |
#region | 它可以让您在使用 Visual Studio Code Editor 的大纲特性时,指定一个可展开或折叠的代码块。 |
#endregion | 它标识着 #region 块的结束。 |
2.9 委托
就是具有相同参数和返回值的函数的模板,但比模板更强大,它还可以组合。(签名什么意思:签名指的是返回值和参数)
委托有啥用?委托解决UI界面控件和其他子线程访问控制控件问题。
//创建线程
Thread th = new Thread(new ThreadStart(test)); //也可简写为new Thread(ThreadMethod);
th.Start(); //启动线程
private void test()
{
for (; ; Thread.Sleep(1000))
{
SetTextCallback d = new SetTextCallback(SetText); // 托管调用
this.Dispatcher.Invoke(d, new object[] { "需要写进去的内容" });
}
}
//UI 主线程
delegate void SetTextCallback(string text); //声明委托
private void SetText(string text)
{
textBox1.Text = text;
}
2.10 lambda表达式
“([参数列表]) => 表达式”: “=>”左边的name定义了参数(当参数个数为1的时候,圆括号可以省略),“=>”右边定义执行体。
Func<函数参数类型,返回值类型> 函数名 = (函数参数) =>{函数体}
- 始终在最后一个类型参数中指定返回值
- lambda表达式,表示一个匿名函数,=>前面的是参数,后面的是函数体。你可以把它当作一个函数。
Func<int, int, int> Add = (x, y) => x + y;Console.WriteLine(Add(2, 3)); // 5
2.11 String
String str1 = "123114511";
//比较
Console.WriteLine (str1.CompareTo ("11344"));//1
Console.WriteLine (String.Compare ("123", "345"));//-1
Console.WriteLine (String.Equals ("2", "3"));//false
//索引
Console.WriteLine (str1.Insert (2, "abc"));//12abc345
//String 类中常用字符串查找 indexOf()函数:在字符串中从前向后定位字符和字符串;
//所有的返回值都是指在字符串的绝对位置,如为空则为- 1。
Console.WriteLine (str1.IndexOf ("34"));//2,返回索引
Console.WriteLine (str1.Trim ('1'));//删除前面的和后面的 1
//C#中没有类似于C++中,string.at的函数 ,但是可以直接用索引
Console.WriteLine (str1 [3]);//2
Console.WriteLine (str1.StartsWith ("123"));//是不是以123开头的,true
常用API函数
INotifyPropertyChanged:监听属性值的变化,当属性值发生改变时,需要被通知,没有改变时不需要通知,属性值改变时触发事件。
ObservableCollection<T>:它实现的接口一个定期收集INotifyCollectionChanged(只要插入新项目,删除(或重新定位)当前项目,或者修改整个集合,就会触发此事件),INotifyPropertyChanged,因此,当您想知道集合何时发生变化时,它非常有用。触发一个事件,告诉用户添加/删除或移动了哪些条目。更重要的是,在表单上使用数据绑定时,它们非常有用。
2.12 ArrayList
优点:
- arrayList的大小是按照其中存储的数据来动态扩充与收缩的
- 在声明arrayList对象时并不需要指定它的长度
- ArrayList可以方便的进行数据的添加add,插入insert()和移除removeAt(index),remove(element)
ArrayList arrLst = new ArrayList();//(底层操作数组)
缺点:
- ArrayList再存储数据时使用object类型进行存储的
- ArrayList不是类型安全的,使用时可能出现类型不匹配的错误
- 插入了同一类型的数据,但是在使用时需要将它们转化为对应的原类型来处理
- ArrayList的存储在装箱(小->大)和拆箱(大->小)的操作,导致其性能低下
2.13 List
泛型<>:限制集合只能存储单一类型数据的手段。
- List和ArrayList都继承了相同的接口,操作类似
- 在声明List时,同时为其声明List集合内数据的对象类型
List<int> i32List = new List<int>();
2.14 Dictionary
- 在声明Dictionary字典时, 需要同时为其声明Dictionary字典内键与值的类型(类似Map)
- 键和值可以是任何类型,但是键是唯一的
- 直接通过键名可以访问和写字典
Dictionary<int, string> dic = new Dictionary<int , string >();//同样有add, remove, insert
dic[键名] = 值, 有.key和.value的属性
2.15 MessageBox
【函数】 <整型> MessageBox(<字符串> Text, <字符串> Title, <整型> nType,MessageBoxIcon);
【函数说明】 弹出一个消息框。
参数:
Text <字符串>,消息框的正文;
Title <字符串>,消息框的标题;
nType <整型>,消息框的类型。
返回值:<整型>,用户在消息框上点击关闭时的选择的按钮。
MessageBoxIcon:对话框上显示的图标样式。
MessageBoxIcon:
- MessageBoxIcon.Question
- MessageBoxIcon.Asterisk
- MessageBoxIcon.Information
- MessageBoxIcon.Error
- MessageBoxIcon.Stop
- MessageBoxIcon.Hand
- MessageBoxIcon.Exclamation
- MessageBoxIcon.Warning
- MessageBoxIcon.None
2.16 Debug
当程序运行时,您可以使用 Debug 类的方法来生成消息,以帮助您监视程序执行顺序、检测故障或提供性能度量信息。
默认情况下,Debug 类产生的消息显示在 Visual Studio 集成开发环境 (IDE) 的“输出”窗口中
使用名字空间: System.Diagnostics
Debug.Print("Today: {0}", DateTime.Today);
Debug.WriteLine("Have a nice day");
Debug.WriteLineIf(IsThursday(), "Thursday");
Debug.Assert(value != -1, "Value must never be -1.");
2.17 TextWriter/TextReader
TextWriter
类是一个抽象类。它用于将文本或连续的字符串写入文件。它在System.IO
命名空间中定义。它们有两个子类:StringReader/StringWriter 用于读取字符串;
StreamReader/StreamWriter 用于读取流;
using System;
using System.IO;
namespace TextWriterExample
{
class Program
{
static void Main(string[] args)
{
using (TextWriter writer = File.CreateText("e:\\TextWriter.txt"))
{
writer.WriteLine("Hello C#, TextWriter");
writer.WriteLine("C# File Handling by Yiibai.com");
}
Console.WriteLine("Data written successfully...");
}
}
}
2.18 ConfigurationManager配置文件
以前使用INI配置文件——用pugixml 对XML解析(C++ INI配置文件——用pugixml 对XML解析(这一篇就够了)_qinze5857的博客-CSDN博客)。在C#中使用ConfigurationManager类来管理配置文件APP.config
命名空间:System.Configuration
程序集: System.Configuration.dll
ConfigurationManager类:
属性:(AppSettings、ConnectionStrings )
方法:(GetSection、OpenExeConfiguration、OpenExeConfiguration、OpenMachineConfiguration、OpenMappedExeConfiguration、OpenMappedExeConfiguration、OpenMappedMachineConfiguration、RefreshSection)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<appSettings>
<add key="Setting1" value="May 5,2018"/>
<add key="Setting2" value="May 5,2017"/>
</appSettings>
</configuration>
获取数据: ConfigurationManager.AppSettings["key"]
System.Configuration 命名空间 | Microsoft Docs
//获取Configuration对象
Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//根据Key读取<add>元素的Value
//string name = config.AppSettings.Settings["Pmin"].Value;
//写入<add>元素的Value
config.AppSettings.Settings["Status"].Value = "0";
//一定要记得保存,写不带参数的config.Save()也可以
config.Save(ConfigurationSaveMode.Modified);
//刷新,否则程序读取的还是之前的值(可能已装入内存)
System.Configuration.ConfigurationManager.RefreshSection("appSettings");
2.19 Thread
线程开始:thread.Start();线程挂起:thread.Suspend();线程继续:thread.Resume();线程终止:thread.Abort();静态方法,暂停当前线程指定的毫秒数: Sleep(int);
注意: abort以后那个线程就不存在了,不可能继续启动,再启动就是新线程了。因此,要暂停线程用Suspend方法,继续的时候用Resume方法。
threadState的使用方法: if (th.ThreadState == (System.Threading.ThreadState.Background |System.Threading.ThreadState.Suspended) ){}
三、Winform控件基本使用
3.1基本控件使用
C#对内部成员访问和结构体一样都是使用“.” , 不可以使用->。
button可以触发Click事件。一般使用MouseUp鼠标弹起事件来替代Click事件,因为Click事件的触发条件比较特殊,而鼠标弹起则每次都会触发。
TextBox允许运行中由用户修改即可以通过键盘删减文本内容,如果将Multiline设为True,那么TextBox便支持多行显示;TextBox的方法最常用的是AppendText方法,将新的文本数据从末尾追加至TextBox中。当一直追加文本后带来无法显示全部文本问题,此时我们需要使能TextBox纵向滚动条来跟踪显示最新文本,ScrollBars = Vertical;如: textBox1.AppendText("C#开发指南\r\n");
RadioButton单选按钮控件使用方法与CheckBox类型,但是CheckBox允许多个进行复选,每个控件之间不存在互斥关系,radiobutton则允许多选,当用户选中其中一个后,其他几个的选中状态全部为false。(并不是多有的radiobutton都会互斥,只有同一容器下才会互斥)
容器控件Panel:容器控件主要用于为其它控件提供一个可识别的分组,比如radiobutton。将panel拖进窗体中时选中区域外会有一个虚线框包围,但窗体运行后,虚线框会消失。
定时器控件(Timer):严格来说Timer是一个组件并不能算作控件,添加timer控件 的方式和普通控件一致,只是添加后控件出现在设计器下方。timer有一个定时的时长,通过设置Timer的interval属性就可以设置定时的时长。注意interval的单位是毫秒(ms),默认为100毫秒触发一次tick事件。启动定时器使用start,停止定时器使用Stop方法。Timer在上位机中可以用于定时发送功能的实现,也可以用作超时处理机制的实现。
串口控件和定时器一样,不需要绘制,因此无法将其添加至窗体中,只能和定时器一样显示在设计器下方。串口的属性有2个,一个是端口号,一个是波特率,其他停止位,校验位等默认即可。串口的函数有open,isOpen,close.串口发送方法有2中,一种是字符串发送writeLine,一种是16进制发送write。其他字符串发送writeLine默认已经在末尾添加换行符。
直接传入要发送的字符串即可,最终发出去的自带换行符。16进制发送一共有3个参数,数组名,起始字节偏移量,发送字节个数
串口接收之前要为串口控件注册一个Receive事件,作用等价于串口接收中断。然后在中断内部对缓冲区进行数据读取。接收有2种方法,一个是16进制方式,一个是字符串方式读取。
定义有效字节数为大小的缓存相当于动态分配,read函数第一个为缓存数组,第二个为偏移量,第三个为写入字节数。
其他控件百度学习或者去MSDN官网学习。在对某个控件或者某个方法的使用不熟悉时可以在代码区选中它,按下“F1”,有帮助文档。
3.2APP执行顺序
Window_Initialized控件初始化
->MainWindow构造函数
->Window_Loaded窗体加载
四、WPF(windows presentation foundation)
WPF(Windows presentation Foundation):新一代的桌面应用程序开发框架,跨平台,让开发界面和后台分离。
WPF和Winform属于两套界面渲染方式。Winform是对传统windows界面元素的封装,通过gdi绘制。WPF是全新的dx渲染绘制的界面,也脱离了对传统windows控件的依赖,没有历史包袱,理论上可以展现更炫酷的界面。
XAML(Extensible Application Markup Language 可扩展应用程序标记语言):专门用于构建应用程序UI
4.1 Window_Loaded()
就是窗体加载的方法,想在窗体加载时完成什么,就可以往这个函数加自己的逻辑代码;其执行顺序是Window_Initialized
->MainWindow
->Window_Loaded。
4.2 FindWindow()
功能:该函数获得一个顶层窗体的句柄,该窗体的类名和窗体名与给定的字符串相匹配。这个函数不查找子窗体。在查找时不区分大写和小写。
HWND FindWindow(LPCTSTR IpClassName,LPCTSTR IpWindowName)
IpClassName :指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。假设该参数为一个成员,则它必须为前次调用theGlobafAddAtom函数产生的全局成员。该成员为16位,必须位于IpClassName的低 16位,高位必须为 0。
IpWindowName:指向一个指定了窗体名(窗体标题)的空结束字符串。假设该参数为空,则为全部窗体全匹配。
返回值:假设函数成功,返回值为具有指定类名和窗体名的窗体句柄;假设函数失败,返回值为NULL。
4.3 DataContext属性
是FrameworkElement.DataContext 属性:获取或设置元素参与数据绑定时的数据上下文。数据上下文 是一种概念,允许元素从父元素继承有关用于绑定的数据源以及绑定的其他特征(如路径)的信息。
4.4 Dispatcher.Invoke
WPF规定:UI元素只能由其主线程来操作,其他任何线程都不可以直接操作UI。而实时的下载进度又不能通过调用某个回调函数来完成更新UI。
WPF中的UI控件,如果我们探究本质,他们都是从DispatcherObject继承,所以都必须由UI线程进行调度和使用,如果我们在其他的后台线程中操作界面相关的元素时,就会出现如下的异常信息:调用线程无法访问此对象,因为另一个线程拥有该对象。Dispatcher.Invoke方法 - smallerpig - 博客园 (cnblogs.com)
方法:
在主线程中定义一个委托,及一个相应的UI控件更新函数;
在子线程中使用Dispatcher.Invoke
this.Dispatcher.Invoke(
new Action( () =>{函数体} //lambda表达式 )
);
Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托
Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。
Control的Invoke和BeginInvoke 是相对于支线线程(因为一般在支线线程中调用,用来更新主线程ui)Invoke立即插入主线程中执行,而BeginInvoke 要等主线程结束才执行
4.5 Action
Action<T>是.NET Framework内置的泛型委托,可以使用Ac
tion<T>委托以参数形式传递方法,而不用显示声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能有返回值。C#内置泛型委托:Action委托 - .NET开发菜鸟 - 博客园 (cnblogs.com)
4.7 Thread
ThreadStart这个委托定义为void ThreadStart(),也就是说,所执行的方法不能有参数。
ParameterThreadStart的定义为void ParameterizedThreadStart(object state)使用这个这个委托定义的线程的启动函数可以接受一个输入参数
Thread tThreadParserFile = new Thread(new ParameterizedThreadStart(ThreadParserFile));
tThreadParserFile.Start();
4.8命名空间
xmlns: x="URL"是XMAL命名空间,它包含各种XMAL实用特性,这些特性可以影响文档的解析方式。该命名空间被映射为前缀x。使用方法: 在元素命名之前放置,例如<x:abc>
xaml命名空间和C#代码中的using是一样的, X名称空间里面的成员(如X:Name,X:Class)都是写给XAML编译器看的、用来引导XAML编译器将XAML代码编译为CLR代码
与C#语言一样,XAML也有自己的编译器。XAML语言被解析并编译,最终形成微软中间语言保存在程序集中。在解析和编译XAML的过程中,我们经常要告诉编译器一些重要的信息,如XAML编译的结果应该和哪个C#代码编译的结果合并、使用XAML声明的元素是public还是private访问级别等等。这些让程序员能够与XAML编译器沟通的工具就存在X:名称空间中
4.9 initializeComponent
当编译应用程序时,定义用户界面的 XAML(如 Window1.xaml)被转换为 CLR 类型声明,这些类型声明和代码隐藏类文件(如 Window1.xaml.cs)中逻辑代码融合到一起,形成单一的单元。在Window1 类尚不具备有任何真正的功能,但它却包含了一个非常重要的细节 ——默认构造函数,当创建类的一个实例时,该构造函数调用 InitializeComponent() 方法。
InitializeComponent() 方法在源代码中是不可见的,因为它是在编译应用程序时自动生成的。本质上,InitializeComponent() 方法的所有工作就是调用 System.Windows.Application 类的LoadComponent() 方法。LoadComponent() 方法是从程序集中提取 BAML,并使用它构造用户界面。当解析BAML时,它会创建每个控件对象,设置其属性,并关联所有事件处理程序。
InitializeComponent() 方法反映了窗体设计器中窗体和控件的属性。通常不会在这个文件中修改代码。如果更改InitializeComponent()方法中的相关属性参数,在窗体设计器界面上也会显示出来。
参考:
C上位机实战开发:https://wenku.baidu.com/view/a5e17408a66e58fafab069dc5022aaea998f417e.html
C# 构造函数总结 - 苍 - 博客园 (cnblogs.com)
WPF与winform区别:https://blog.csdn.net/qq_44034384/article/details/106049488
WPF中MainWindow、Window_Loaded、Window_Initialized的执行顺序_ShineRoyal-CSDN博客
C#中定义数组--字符串及数组操作 - swtool - 博客园 (cnblogs.com)
C# WPF 线程中更改textbox内容_soekchl521的博客-CSDN博客
Dispatcher.Invoke方法 - smallerpig - 博客园 (cnblogs.com)
【C#学习笔记】使用C#中的Dispatcher - 简书 (jianshu.com)
C#中Invoke 和 BeginInvoke 的区别 - asdyzh - 博客园 (cnblogs.com)
如何使用C#的方法 Dispatcher.Invoke =>_百度知道 (baidu.com)
C#内置泛型委托:Action委托 - .NET开发菜鸟 - 博客园 (cnblogs.com)
C#跟踪和调试程序-Debug类使用 - gsk99 - 博客园 (cnblogs.com)
c# TextReader/TextWriter 的类 - 银河系上的地球 - 博客园 (cnblogs.com)
C# ConfigurationManager 类的使用 - 周兴兴 - 博客园 (cnblogs.com)
WPF InitializeComponent() 方法介绍 - Andrew.Wangxu - 博客园 (cnblogs.com)
WPF中MainWindow、Window_Loaded、Window_Initialized的执行顺序_ShineRoyal-CSDN博客
标签:控件,C#,干货,线程,new,窗体,全解,构造函数 来源: https://blog.csdn.net/qinze5857/article/details/115666200
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。