教你如何建设一个模板网站,怎么做一个网站多少钱,做网站兼职,确认已有81人感染C#使用ListView更新数据出现闪烁解决办法 在使用vs自动控件ListView控件时候#xff0c;更新里面的部分代码时候出现闪烁的情况 如图#xff1a; 解决以后#xff1a; 解决办法使用双缓冲#xff1a;添加新类继承ListView 对其重写 1 public class DoubleBufferListView : …C#使用ListView更新数据出现闪烁解决办法 在使用vs自动控件ListView控件时候更新里面的部分代码时候出现闪烁的情况 如图 解决以后 解决办法使用双缓冲添加新类继承ListView 对其重写 1 public class DoubleBufferListView : ListView2 {3 public DoubleBufferListView()4 {5 SetStyle(ControlStyles.DoubleBuffer |6 ControlStyles.OptimizedDoubleBuffer |7 ControlStyles.AllPaintingInWmPaint, true);8 UpdateStyles();9 }
10 } 新建一个DemoTest测试 1.添加一个DoubleBufferListView的实例 DoubleBufferListView doubleBufferListView1 new DoubleBufferListView();// // doubleBufferListView1// this.doubleBufferListView1.Font new System.Drawing.Font(微软雅黑, 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));this.doubleBufferListView1.FullRowSelect true;this.doubleBufferListView1.HideSelection false;this.doubleBufferListView1.Location new System.Drawing.Point(50, 37);this.doubleBufferListView1.Name doubleBufferListView1;this.doubleBufferListView1.Size new System.Drawing.Size(400, 191);this.doubleBufferListView1.TabIndex 2;this.doubleBufferListView1.UseCompatibleStateImageBehavior false;this.doubleBufferListView1.View System.Windows.Forms.View.Details; 2.将其添加到form窗体里面 this.Controls.Add(this.doubleBufferListView1); 3.给添加列 doubleBufferListView1.Clear();doubleBufferListView1.Columns.Add(Action, 80, System.Windows.Forms.HorizontalAlignment.Left);doubleBufferListView1.Columns.Add(value, 80, System.Windows.Forms.HorizontalAlignment.Right);doubleBufferListView1.Columns.Add(Action, 80, System.Windows.Forms.HorizontalAlignment.Left);doubleBufferListView1.Columns.Add(value, 80, System.Windows.Forms.HorizontalAlignment.Left); 4.随便添加点内容 string[] listViewData new string[4];listViewData[0] Action;listViewData[1] 1;listViewData[2] Action;listViewData[3] 1;ListViewItem lvItem new ListViewItem(listViewData, 0);doubleBufferView1.Items.Add(lvItem); 5.点击按钮开始运行 private void button1_Click(object sender, EventArgs e){Thread th new Thread(PlayGame);if (state false){state true;button1.Text 停止;th.IsBackground true;th.Name 新线程;th.Start();}else{state false;button1.Text 开始;}}private void PlayGame(){Random r new Random();while (state){string temp r.Next(0, 10).ToString();label1.Text temp;this.doubleBufferListView1.Items[0].SubItems[1].Text temp;}} 6.运行对比图 左侧是解决闪屏后右侧是自带的ListView效果 原文链接https://www.cnblogs.com/JiYF/p/6233313.html C#中Invoke的用法 在用.NET Framework框架的WinForm构建GUI程序界面时如果要在控件的事件响应函数中改变控件的状态例如某个按钮上的文本原先叫“打开”单击之后按钮上的文本显示“关闭”初学者往往会想当然地这么写 void ButtonOnClick(object sender,EventArgs e) { button.Text关闭; } 这样的写法运行程序之后可能会触发异常异常信息大致是“不能从不是创建该控件的线程调用它”。注意这里是“可能”并不一定会触发该种异常。造成这种异常的原因在于控件是在主线程中创建的比如this.Controls.Add(...);)进入控件的事件响应函数时是在控件所在的线程并不是主线程。在控件的事件响应函数中改变控件的状态可能与主线程发生线程冲突。如果主线程正在重绘控件外观此时在别的线程改变控件外观就会造成画面混乱。不过这样的情况并不总会发生如果主线程此时在重绘别的控件就可能逃过一劫这样的写法可以正常通过没有触发异常。 正确的写法是在控件响应函数中调用控件的Invoke方法其实如果大家以前用过C Builder的话也会找到类似Invoke那样的激活到主线程的函数。Invoke方法会顺着控件树向上搜索直到找到创建控件的那个线程通常是主线程然后进入那个线程改变控件的外观确保不发生线程冲突。正确写法的示例如下 void ButtonOnClick(object sender,EventArgs e) { button.Invoke(new EventHandler(delegate { button.Text关闭; })); } Invoke方法需要创建一个委托。你可以事先写好函数和与之对应的委托。不过若想直观地在Invoke方法调用的时候就看到具体的函数而不是到别处搜寻的话上面的示例代码是不错的选择。 这样的写法有一个烦人的地方对不同的控件写法不同。对于TextBox要TextBoxObject.Invoke对于Label又要LabelObject.Invoke。有没有统一一点的写法呢 主窗口类本身也有Invoke方法。如果你不想对不同的控件写法不一样可以全部用this.Invoke void ButtonOnClick(object sender,EventArgs e) { this.Invoke(new EventHandler(delegate { button.Text关闭; })); } 在C# 3.0及以后的版本中有了Lamda表达式像上面这种匿名委托有了更简洁的写法。.NET Framework 3.5及以后版本更能用Action封装方法。例如以下写法可以看上去非常简洁 void ButtonOnClick(object sender,EventArgs e) { this.Invoke(new Action(() { button.Text关闭; })); } 以上写法往往充斥着WinForm构建的程序。 在微软新一代的界面开发技术WPF中由于界面呈现和业务逻辑原生态地分开在两个线程中所以控件的事件响应函数就不必Invoke了。但是如果手动开辟一个新线程那么在这个新线程中改变控件的外观则还是要Invoke的。 当一个控件的InvokeRequired属性值为真时说明有一个创建它以外的线程想访问它此时它将会在内部调用new MethodInvoker(LoadGlobalImage)来完成下面的步骤这个做法保证了控件的安全你可以这样理解有人想找你借钱他可以直接在你的钱包中拿这样太不安全因此必须让别人先要告诉你你再从自己的钱包把钱拿出来借给别人这样就安全了 another 在设计中为了让界面与逻辑分离我的做法是使用事件界面只要响应事件来处理界面的显示就行了。而事件在逻辑处理中可能由不同的线程引发这些事件的响应方法在修改界面中的控件内容时便会引发一个异常。 这时就用到了Control.InvokeRequired 属性 与Invoke方法。 MSDN中说获取一个值该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法因为调用方位于创建控件所在的线程以外的线程中。 如果控件的 Handle 是在与调用线程不同的线程上创建的说明您必须通过 Invoke 方法对控件进行调用则为 true否则为 false。Windows 窗体中的控件被绑定到特定的线程不具备线程安全性 。因此如果从另一个线程调用控件的方法那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于确定是否必须调用 Invoke 方法当不知道什么线程拥有控件时这很有用。 下面来说下这个的用法我的一般做法首先定义一个委托与这个事件处理函数的签名一样委托当然直接使用该事件的委托也是可以的如 private delegate void InvokeCallback( string msg); 然后就是判断这个属性的值来决定是否要调用Invoke函数 void m_comm_MessageEvent( string msg) { if (txtMessage.InvokeRequired) { InvokeCallbackmsgCallback new InvokeCallback(m_comm_MessageEvent); txtMessage.Invoke(msgCallback, new object [] { msg } ); } else { txtMessage.Text msg; } } 说明这个函数就是事件处理函数txtMessage是一个文本框。这样就做到了窗体中控件的线程安全性。 ------------------ InvokeRequired 当前线程不是创建控件的线程时为true比如你可以自己开一个Thread或使用Timer的事件来访问窗体上的控件的时候在线程中窗体的这个属性就是True的。简单的说如果有两个线程Thread A和Thread B并且有一个Control c是在Thread A里面new的。那么在Thread A里面运行的任何方法调用c.InvokeRequired都会返回false。相反如果在Thread B里面运行的任何方法调用c.InvokeRequired都会返回true。是否是UI线程与结果无关。通常Control所在的线程是UI线程但是可以有例外也可以认为在new Control()的时候control用一个变量记录下了当前线程在调用InvokeRequired时返回当前线程是否不等于new的时候记录下来的那个线程。 -------------------- 我理解如果InvokeRequiredtrue表示其它线程需要访问控件那么调用invoke来转给控件owner处理。 原文链接https://www.cnblogs.com/vaevvaev/p/6909042.html