(15)C#传智:Directory类,控件(Webbrowser,comboBox,listBox,DiaglogBox,Panel),进程与线程(第15天)

一、多余Using


    
    程序首部的using很多没有使用(灰色),有什么影响?
        在已经编译成功后,没有任何影响。它会影响编译时间和Intellisense/IDE响应能力。
 


二、Directory操作文件夹
    


    File、Path、FileStream、StreamReader、StreamWriter
    
    公开用于通过目录和子目录进行创建、移动和枚举的静态方法
    
    Direcory.CreateDirectory(string path)创建文件夹
    
    Directory.Delete(string path)    删除文件夹(必须为空否则异常)
    Directory.Delete(string path,bool recursive) 第二参为true强行删除
    注意:删除操作是彻底删除。回收站是没有东西的。
    
    Directory.Move(string scrDir,string desDir) 移动
    
    Directory.GetFiles(string Path) 获取目录下所有文件,返回全路径的数组
    Directory.GetFiles(string path,string searchPattern) 同上,指定匹配
    
    Directory.GetDirectories(string path) 获取所有子目录,返回数组
    Directory.GetDirectories(string path,string searchPattrern)同上,匹配
    
    Directory.Exist(string path) 是否存在目录,返回bool
    
    注意:File.Create()与File.CreateText()创建的文件,必须用返回值进行关闭
        否则,在后面进行删除时会提示异常。

    private static void Main(string[] args)
    {
        Directory.CreateDirectory(@"E:\a");
        for (int i = 0; i < 6; i++)
        {
            Directory.CreateDirectory(@"E:\a\" + i);
        }

        FileStream fs = File.Create(@"E:\a\cc.doc");
        fs.Close();

        for (int i = 1; i < 5; i++)
        {
            fs = File.Create(@"E:\a\" + i + ".txt");
            fs.Close();
        }

        fs = File.Create(@"E:\a\0\dd.txt");
        fs.Close();
        string[] d = Directory.GetDirectories(@"E:\a");
        foreach (string s in d) { Console.WriteLine(s); }
        Directory.Move(@"E:\a\0", @"E:\a\7");//前面必须有fs.close否则文件未关闭前无法移动,异常
        for (int i = 1; i < 6; i++)
        {
            Directory.Delete(@"E:\a\" + i);
        }
        Directory.Delete(@"E:\a\7", true);

        string[] f = Directory.GetFiles(@"E:\a", "*.txt");
        foreach (string s in f) { Console.WriteLine(s); }
        Directory.Delete(@"E:\a", true);//同样创建的文件也必须关闭
        Console.ReadKey();
    }    


 

    
三、Webbrowser 浏览器控件


    Url    Web浏览器控件导航到的URL
    
    不懂问题的学习方法:
    例如:
    string s=textBox1.Text;
    webBrowser1.Url = s;
    
    在VS中,s出现红色错误:无法将string转为uri,鼠标指向等号左侧Url,提示是一个Uri类型.
    新起一行,写上Uri,变成绿色,鼠标指向它提示Class,说明是一个类;接F12进入内部查看
    Uri定义,如果代码是展开情况,就先折叠(Ctrl+M,Ctrl+O),这样查看就方便多了。
        可以看到Uri类的定义,构造函数有三个,其中带string,就是我们需要的。里面还有
    一些字段和方法,可以大体看一下。
        还有一种直接对Uri用F1到MSDN中查看帮助。
        回到前面构造函数: public Uri(string name)  这样就可以构造由string组成的Url.

        
    string s=textBox1.Text;
    webBrowser1.Url = new Uri(s);


    
    特别小心:Url与Uri是不一样的

    
    webBrowser1.Url = new Uri("http://" + textBox1.Text);


    或者直接:

    webBrowser1.Navigate("http://www.baidu.com");


    
    小技巧:
        当有时多添加了控件,要删除控件,或者修改控件名,或者删除控件事件等等,当删除后
    返回切换到设计界面时,会提示错误,某行某错误,可以直接点进去,删除红线部分行。
        另一个比较好的方法就是,当在界面删除控件后,在菜单中:生成->重新生成解决方法,
    查看下面的错误提示,对应删除相关问题,再一次:生成->重新生成解决方法,直到没有红色
    错误提示。
        前面的方法有时会使整个程序崩溃,只有重建程序。后者目前还没发现过崩溃,比较高效
    安全。


四、ComboBox下拉条


    添加下拉数据:Items集合

    comboBox1.Items.Add("张三");
    comboBox1.Items.Add("李四");
    comboBox1.Items.Add("王五");
    comboBox1.Items.Add("张三")


    
    删除数据:

    comboBox1.Items.Remove("张三");//删除第一个张三,无张三不会有错
    comboBox1.Items.RemoveAt(1);   //删除索引1的项,无该索引出错.


    
    下拉样式DropDownStyle
    DropDown    下拉样式(默认),可修改Text属性.一行
    Simple      展开样式,可修改Text属性.多行
    DropDownList 下拉样式,不可修改Text属性.一行
    
    
    控制下拉条的高度
    先将IntegralHeight设置为false,以便下面设置生效:

    comboBox1.Height = 10;  //设置高度(像素)
    comboBox1.MaxDropDownItems = 5;//设置最大显示项


    
    练习题:三鼐下拉框,分别为年、月、日的选择。根据选择分别显示。
    
    界面:

    

 

    private void Form1_Load(object sender, EventArgs e)
    {
        cboYear.IntegralHeight = false;//这样才能控制高度
        cboMonth.IntegralHeight = false;
        cboDay.IntegralHeight = false;
        cboYear.MaxDropDownItems = 12;
        cboMonth.MaxDropDownItems = 12;
        cboDay.MaxDropDownItems = 12;
        int year = DateTime.Now.Year;
        for (int i = year; i >= 1949; i--)//倒序符合人性
        {
            cboYear.Items.Add(i + "年");
        }
    }

    private void cboMonth_SelectedIndexChanged(object sender, EventArgs e)
    {
        string strD = cboDay.Text.TrimEnd('日');
        string y = cboYear.SelectedItem.ToString().TrimEnd('年');
        string m = cboMonth.SelectedItem.ToString().TrimEnd('月');
        int days = DateTime.DaysInMonth(Convert.ToInt32(y), Convert.ToInt32(m));
        cboDay.Items.Clear();
        for (int i = 1; i <= days; i++)
        {
            cboDay.Items.Add(i + "日");
        }

        if (strD != "")//切换月数时,保持日数
        {
            if (Convert.ToInt32(strD) > days) cboDay.Text = days + "日";
            else cboDay.Text = strD + "日";
        }
    }

    private void cboYear_SelectedIndexChanged(object sender, EventArgs e)
    {
        string strM = cboMonth.Text;
        cboMonth.Items.Clear();

        for (int i = 1; i < 13; i++)
        {
            cboMonth.Items.Add(i + "月");
        }
        cboMonth.Text = strM;//切换年时保持月份
    }


    
    
五、ListBox列表框


    selectedIndex 已选定项的索引
    selectedItem 已经选定的项

    练习:
        列出文件夹中所有图片,点击其一则显示图片。
        
    界面:


    

 

    private List<string> lst = new List<string>();

    private void Form1_Load(object sender, EventArgs e)
    {
        string[] p = Directory.GetFiles(@"E:\pic", "*.png");

        for (int i = 0; i < p.Length; i++)
        {
            string f = Path.GetFileName(p[i]);
            listBox1.Items.Add(f);
            lst.Add(p[i]);
        }
        pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
    }

    private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        pictureBox1.Image = Image.FromFile(lst[listBox1.SelectedIndex]);
    }


    
    练习题:剪刀石头布,玩家与电脑玩
    石头1,剪刀2,布3
    玩家赢:1-2=-1,2-3=-1,3-1=2
    玩家平:0
    玩家胜:其余
    
    界面:


    
    构建三个类。玩家类:出拳方法。电脑类:出拳方法。电脑类:比较。

 

    internal class Player
    {
        public int ShowFist(string fist)
        {
            switch (fist)
            {
                case "石头": return 1; break;
                case "剪刀": return 2; break;
                default: return 3; break;
            }
        }
    }


    
    电脑类,需要一个属性,以显示在lable上

    internal class Computer
    {
        public string Fist
        {
            get; set;
        }

        public int ShowFist()
        {
            Random r = new Random();
            int n = r.Next(1, 4);
            switch (n)
            {
                case 1: Fist = "石头"; break;
                case 2: Fist = "剪刀"; break;
                default: Fist = "布"; break;
            }
            return n;
        }
    }


    
    裁判类,加入枚举。

    public enum Result
    {
        玩家胜,
        电脑胜,
        平手
    }

    internal class Judgment
    {
        public static Result Judge(int player, int computer)//静态
        {
            int n = player - computer;
            switch (n)
            {
                case -1:
                case 2:
                    return Result.玩家胜;
                    break;

                case 0:
                    return Result.平手;
                    break;

                default:
                    return Result.电脑胜;
                    break;
            }
        }
    }


    
    主程序,初始化后,用一个通用方法比较:
    技巧:对于vs2022,发现里面可以写成通用方法时,选择这些代码右击->快速操作与重构。
    弹出提示中选择:提取方法,回车,重命名方法,即得通用方法。
    

    private void Form1_Load(object sender, EventArgs e)
    {
        lblComp.Text = "";
        lblPlayer.Text = "";
        lblResult.Text = "";
        this.CenterToScreen();
    }

    private void btnStone_Click(object sender, EventArgs e)
    {
        string strFist = "石头";
        GetResult(strFist);
    }

    private void btnCut_Click(object sender, EventArgs e)
    {
        string strFist = "剪刀";
        GetResult(strFist);
    }

    private void btnCloth_Click(object sender, EventArgs e)
    {
        string strFist = "布";
        GetResult(strFist);
    }

    private void GetResult(string strFist)
    {
        Player p = new Player();
        int np = p.ShowFist(strFist);
        lblPlayer.Text = strFist;
        Computer c = new Computer();
        int nc = c.ShowFist();
        lblComp.Text = c.Fist;

        lblResult.Text = Judgment.Judge(np, nc).ToString();
    }


    

六、DialogBox对话框

 
    1、OpenFileDialog 打开文件对话框
    
    Title        对话框标题
    Multiselect  可以多选文件bool,为true
    InitialDirectory  打开的初始目录位置
    Filter         打开文件的类型筛选,"文本文件|*.txt|媒体文件|*.wav|图片文件|*.jpg"
    
    FileName    获得的文件,单个
    FileNames   获得的文件,多个
    
    练习:打开一个文本文件。
    除去对话框外,读文件用两种:一个是StreamReader适合字符;另一个是FileStream适合所有。
    本例主要说明读取大文件时的问题。
    
        当用FileStream最后一次读取时,一般会出现不满字节数组buffer的问题,这里有一个返
    回值count显示了读取的真实长度,如果小于规定的buffer的长度,说明这是最后一次了。如
    果直接用buffer读取,则真实长度count后面的长度(buffer.length-count)就是倒数第二次读
    取时填充的数据。
        为了避免这种情况,应该在每次填充数据时进行清空Array.Clear(),这样每次字节数组
    都是空的"\0"。但转换的s(s2)是由buffer而来,所以它是buffer.length的整数倍。
        要查看就在最后次显示最后的数组。txtText中显示了最后一次最后几个字符的ASC码,所
    以看到回车换行(13,10)以及最后的z(122)后面的结尾"\0".
    
    界面:


    
  

 代码:

 

    private void Form1_Load(object sender, EventArgs e)
    {
        this.CenterToScreen();
    }

    private void btnBrowser_Click(object sender, EventArgs e)
    {
        dlgOpenFile.InitialDirectory = @"E:\";
        dlgOpenFile.Filter = "文本文件|*.txt";
        string s1 = "", s2 = "", s = "";
        if (dlgOpenFile.ShowDialog() == DialogResult.OK)
        {
            string f = dlgOpenFile.FileName;
            using (StreamReader rs = new StreamReader(f, Encoding.Default))
            {
                s1 = rs.ReadToEnd();
            }
            txtText1.Text = s1;

            int count = 0;
            using (FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read))
            {
                byte[] buffer = new byte[8];

                do
                {
                    Array.Clear(buffer, 0, buffer.Length);
                    count = fs.Read(buffer, 0, buffer.Length);
                    s = Encoding.Default.GetString(buffer);
                    if (count < buffer.Length)//显示最后一次读取的末尾数据
                    {
                        for (int i = 0; i < count; i++)
                        {
                            txtText3.Text += s[i].ToString();
                        }//count=6,,-121-13-10-122  13:回车,10:换行,超出部分的ASC为0
                        txtText3.Text += "-" + (int)s[2] + "-" + (int)s[3] + "-" + (int)s[4] + "-" + (int)s[5] + "-" + (int)s[6];
                    }
                    s2 += s;
                } while (count == buffer.Length);
            }
            txtText2.Text = s2;
            MessageBox.Show(count + "_" + s1.Length + "_" + txtText1.Text.Length + "_" + s2.Length + "_" + txtText2.Text.Length);
        }
    }


    
    
    2、SaveFileDialog 保存文件对话框 
    
    Title     对话框标题
    InitialDirectory  初始目录
    Filter            类型筛选器
    Filename          返回的文件的全路径,已经存在会提示覆盖
    
    练习:保存textBox中的字符到文件.
    
    界面:


    
  

 代码:

 

    private void button1_Click(object sender, EventArgs e)
    {
        dlgSave.Title = "请选择保存的文件";
        dlgSave.InitialDirectory = @"E:\";
        dlgSave.Filter = "文本文件|*.txt";
        if (dlgSave.ShowDialog() == DialogResult.OK)
        {
            using (FileStream fs = new FileStream(dlgSave.FileName, FileMode.OpenOrCreate, FileAccess.Write))
            {
                byte[] buffer = Encoding.Default.GetBytes(textBox1.Text);
                fs.Write(buffer, 0, buffer.Length);
            }
        }
    }


    
    
    3、FontDialog与ColorDialog  字体对话框与颜色对话框
    
    一般使用对应的类,用ShowDialog与对象的赋值来操作。
    
    练习:设置textBox的字体与颜色
    界面:

 


    代码:

    private void button1_Click(object sender, EventArgs e)
    {
        FontDialog fd = new FontDialog();
        fd.ShowDialog();
        textBox1.Font = fd.Font;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        ColorDialog cd = new ColorDialog();
        cd.ShowDialog();
        textBox1.ForeColor = cd.Color;
    }


    
    
七、Panel容器


    panel本身不显示,只作容器。visible显示时其内控件显示,否则隐藏。
    
    练习:简单记事本。
    文件:打开,保存;格式:颜色与字体;换行,最后一个历史记录。
    历史记录:在每次打开时,在全局list<string> lst中保存全路径。这样查找历史记录list1时
    双击selectedItem就可直接调用lst的全路径,从而打开文件到文本框中。
    
    
    界面:

 


    代码:

    
    private List<string> lst = new List<string>();//装入各个历史打开文件全路径

    private void Form1_Load(object sender, EventArgs e)
    {
        this.CenterToScreen();
        panel1.Visible = false;
        textBox1.WordWrap = false;
    }

    private void 字体ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        FontDialog fd = new FontDialog();
        fd.ShowDialog();
        textBox1.Font = fd.Font;
    }

    private void 颜色ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        ColorDialog cd = new ColorDialog();
        cd.ShowDialog();
        textBox1.ForeColor = cd.Color;
    }

    private void 自动换行ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if (自动换行ToolStripMenuItem.Text == "自动换行")
        {
            textBox1.WordWrap = true;
            自动换行ToolStripMenuItem.Text = "取消换行";
        }
        else
        {
            textBox1.WordWrap = false;
            自动换行ToolStripMenuItem.Text = "自动换行";
        }
    }

    private void 显示ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        panel1.Visible = true;
    }

    private void 隐藏ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        panel1.Visible = false;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        panel1.Visible = false;
    }

    private void 打开ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        OpenFileDialog ofd = new OpenFileDialog();
        ofd.Title = "打开文本文件";
        ofd.InitialDirectory = @"E:\";
        ofd.Filter = "文本文件|*txt|全部文件|*.*";
        ofd.Multiselect = false;
        if (ofd.ShowDialog() == DialogResult.OK)
        {
            string f = Path.GetFileName(ofd.FileName);

            listBox1.Items.Add(f);
            lst.Add(ofd.FileName);
            OpenToText(ofd.FileName);
        }
    }

    private void 保存ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        SaveFileDialog sfd = new SaveFileDialog();
        sfd.Title = "保存文件";
        sfd.InitialDirectory = @"E:\1";
        sfd.Filter = "文本文件|*.txt";
        if (sfd.ShowDialog() == DialogResult.OK)
        {
            using (FileStream fs = new FileStream(sfd.FileName, FileMode.OpenOrCreate, FileAccess.Write))
            {
                byte[] buffer = Encoding.Default.GetBytes(textBox1.Text);
                fs.Write(buffer, 0, buffer.Length);
            }
        }
    }

    private void OpenToText(string f)
    {
        using (FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read))
        {
            byte[] buffer = new byte[1024 * 1024 * 5];
            int count = fs.Read(buffer, 0, buffer.Length);
            textBox1.Text = Encoding.Default.GetString(buffer, 0, count);
        }
    }

    private void listBox1_DoubleClick(object sender, EventArgs e)
    {
        string s = lst[listBox1.SelectedIndex];
        OpenToText(s);
    }

    
八、Process进程


    1、关于进程与线程的形象比喻:
    操作系统的设计,可以归结为三点:
        (1)以多进程形式,允许多个任务同时运行;
        (2)以多线程形式,允许单个任务分成不同的部分运行;
        (3)提供协调机制,一方面防止进程之间和线程之间产生冲突,
                            另一方面允许进程之间和线程之间共享资源。
    
    CPU:承担所有计算任务,如同一座工作,时刻在运行。(内有多个车间)
    进程:工厂的一个车间。电力有限时只能供一车间(进程)使用,表示单核CPU只能运行一个任务。
    线程 :车间里的工人。一个车间(进程)可以有多个工人(线程).
    
    车间的空间(进程的内存空间)是工人(线程)共享的。车间里工人们可共享的洗澡间,厕所等。
    
    车间(进程)里有些房间只能容纳1个工人(线程),如厕所、澡堂等。只有使用完了,后面工人(线程)才能
    使用。代表有些共享内存存在线程占用时,其它线程不得访问。
    
    一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,
    等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 MutEx),防止多个线程同时读写某一块内
    存区域。
    
    还有些房间,可以同时容纳n个工人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。
    这好比某些内存区域,只能供给固定数目的线程使用。
    
    这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现
    钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore)。
    
    信号量用来保证多个线程不会互相冲突。MutEx是semaphore的一种特殊情况(n=1时)。即,完全可以用后者
    替代前者。但是,因为MutEx较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
    
    信号量Semaphore:车间内可以同时进多人的多人间,门口挂n把开门钥匙,以此判断工人(线程)是否等待。
    
    
    2、Process类 
    
    Process.GetProcess()
    Kill()  强制终止基础进程。方法 Kill 强制终止进程,而CloseMainWindow 仅请求终止。当具有图形界面的
            进程正在执行时,其消息循环处于等待状态。 每当操作系统将 Windows 消息发送到进程时,都会执
            行消息循环。 调用 CloseMainWindow 发送关闭主窗口的请求,该请求在格式正确的应用程序中关闭
            子窗口并撤消应用程序的所有正在运行的消息循环。 通过调用 CloseMainWindow 退出进程的请求不
            会强制应用程序退出。 应用程序可以在退出前要求用户验证,也可以拒绝退出。 若要强制退出应用
            程序,请使用 Kill 方法。
    CloseMainWindow()  通过向进程的主窗口发送关闭消息来关闭拥有用户界面的进程。
    Process.Star()
    
    
    练习一:列举进程,调用常用程序

    private static void Main(string[] args)
    {
        Process[] p = Process.GetProcesses();
        foreach (Process p2 in p)
        {
            //p2.Kill();
            Console.WriteLine(p2);
        }

        Process.Start("IExplore.exe");//IE
        Process.Start("iexplore");
        Process.Start("iexplore", "https://www.baidu.com");
        Process.Start("notepad.exe");//记事本
        Process.Start("notepad");
        Process.Start("notepad", "E:\\1.txt");
        Process.Start("calc");  //计算器
        Process.Start("calc.exe");
        Process.Start("mspaint");//画图
        Console.ReadKey();
    }


    
    练习二:调用进程打开种类文件

    private static void Main(string[] args)
    {
        //ProcessStartInfo psi = new ProcessStartInfo(@"E:\1.txt");
        //Process p = new Process();
        //p.StartInfo = psi;
        //p.Start();

        Process p = new Process();
        p.StartInfo = new ProcessStartInfo(@"E:\1.txt");
        p.Start();

        Console.ReadKey();
    }


    
    
    
九、线程


    1、单线程的问题:假死。
    VS中当运行程序时,会分配一个主线程来运行这个程序,主线程结束时,程序就结束了。
    如果主线程忙于计算而“抽不出身”时,对窗体或控件就来不及响应,出现假死现象。
    
    例:一窗体添加一button,内加代码,当点击button时,一直显示输出窗体,这时移动窗体
    程序不会“响应”,因为它“忙”于显示去了。
    小技巧:如何显示窗体中的Console.WriteLine()?
        vs2022: 调试->窗口->输出,再运行程序,就可以看到输出窗口中的Console.WriteLine.

    private void button1_Click(object sender, EventArgs e)
    {
        Test();
    }

    private void Test()
    {
        for (int i = 0; i < 1000000; i++)
        {
            Console.WriteLine(i);
        }
    }


    
    主线程一个人在完成移动窗体、窗体大小变化、控件事件、程序运行、计算等等,只要有一个
    任务比较“繁重”时,主线程就会“忙“不过来,对其它的响应“看似”不响应,就出现“假死”现象。
    
    2、新创建一个线程
    using System.Threading;
    实例Thread类,并传入一个指向线程所要运行方法的委托。这时候线程已经产生,但还未用运行。
    
    调用Thread实例的Start方法,并不是开始执行。它是所CPU说明我已经准备OK了,具体执行时间
    由CPU决定,也许CPU很忙,就得等待了。

    
        
    当关于主窗体时,可能会发现线程还在继续执行,Why?
    
    线程分类:
    1)前台线程:只有所有的前台线程都关闭,才能完成的程序关闭。
    2)后台线程:只要所有的前台程序结束,后台线程自动马上结束。
    
    默认情况下,创建的线程都是前台线程。虽然关闭了主窗体,但前台线程没有结束,所以程序还
    没有关闭。所以还可以看到下面输出窗体的显示。
    
    因为要避免上面线程还在继续的情况,可以把线程设置为后台线程,只要前台一结束,这个后台
    的线程就会马上结束。
    
    在.Net下,是不允许跨线程访问的
    
    取消跨线程的访问: 
        Control.CheckForIllegalCrossThreadCalls = false;//不检测跨线程
    
    当线程在执行时,关闭主程序。主窗体中的控件释放,而线程仍然在访问主窗体里的控件。
    这样会出现异常。
    
    解决办法:在关闭主窗体时,对线程进行检测,如果不为null应该强行关闭线程,以防止
    它对窗体控件的继续访问。即在FormClosing事件中写入判断。
    
    Abort()  中止线程。中止完成后不能再重启Start()
 

        t.Start();
        t.Abort();
        t.Start();//错误,不能重启


    Name  线程名
    Thread.CurrentThread 获得当前的线程引用
    Thread.Sleep(1000)  将当前线程挂起指定的毫秒数。
    

    private void button1_Click(object sender, EventArgs e)
    {
        Thread t = new Thread(Test);
        t.IsBackground = true;//设置为后台线程
        t.Start();
    }

    private void Test()
    {
        for (int i = 0; i < 100000; i++)
        {//主线程textBox1不能被新线程访问
            textBox1.Text = i.ToString();
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Control.CheckForIllegalCrossThreadCalls = false;//不检测跨线程
    }


    

   
    

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值