麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

.net類庫里L(fēng)istView的一個BUG

2019-11-17 02:45:23
字體:
供稿:網(wǎng)友
.net類庫里L(fēng)istView的一個BUG

今天在CSDN論壇里看一個帖子,說是在ListView中添加了條目后第一行內(nèi)容不顯示,為了還原他的問題我寫了以下代碼。

復(fù)制代碼 PRivate void LoadFiles(DirectoryInfo dir) { FileInfo[] files = dir.GetFiles(); foreach (FileInfo file in files) { ListViewItem item = new ListViewItem(); item.Tag = file; item.SubItems.AddRange(SubItems.ToArray()); listView1.Items.Add(item); UpdateItem(item); } } ListViewItem.ListViewSubItem[] SubItems { get { return new ListViewItem.ListViewSubItem[] { new ListViewItem.ListViewSubItem(), new ListViewItem.ListViewSubItem() }; } } private void UpdateItem(ListViewItem item) { FileInfo info = (FileInfo)item.Tag; item.Text = info.Name; item.SubItems[1].Text = info.Length.ToString("N0"); item.SubItems[2].Text = info.LastWriteTime.ToString(); }復(fù)制代碼ListView共有3列,分別顯示文件名、大小和最后修改時間,運行以后我發(fā)現(xiàn),文件名可以顯示,但是后面2列不能顯示。經(jīng)過各種調(diào)試和偶遇,終于讓我發(fā)現(xiàn),只要改變ListViewItem.Text的值,后面兩列的內(nèi)容就能夠顯示了,于是初步解決方案是改變ListViewItem.Text的賦值順序,把它放在所有SubItem.Text賦值以后再賦值。為了找到根本原因,我翻查了.net類庫的源代碼,最后終于發(fā)現(xiàn)問題所在,先來看看ListViewSubItem.Text的源代碼。復(fù)制代碼 public string Text { get { return text == null ? "" : text; } set { text = value; if (owner != null) { owner.UpdateSubItems(-1); } } }復(fù)制代碼在對此屬性賦值時,首先檢查owner字段的值是否為空,如果不為空才調(diào)用owner.UpateSubItems方法對ListView進行更新。很明顯,出現(xiàn)上面的問題時,owner值一定為空,通過在VS里調(diào)試證實了這點。現(xiàn)在的問題是,為什么這owner會為空,owner的類型是ListViewItem,從字面理解它應(yīng)該是SubItem所屬的那個行項目,正常情況下在添加到ListViewItem.SubItems以后就應(yīng)該不會為空,于是我猜是在添加的時候這個owner沒有被賦值。后來通過查看源代碼以后證實了我的想法,來看看ListViewSubItemCollection關(guān)于添加子項的源碼。復(fù)制代碼 public ListViewSubItem Add(ListViewSubItem item) { EnsureSubItemSpace(1, -1); item.owner = this.owner; owner.subItems[owner.SubItemCount] = item; owner.UpdateSubItems(owner.SubItemCount++); return item; } public void AddRange(ListViewSubItem[] items) { if (items == null) { throw new ArgumentNullException("items"); } EnsureSubItemSpace(items.Length, -1); foreach(ListViewSubItem item in items) { if (item != null) { owner.subItems[owner.SubItemCount++] = item; } } owner.UpdateSubItems(-1); }復(fù)制代碼很明顯,Add方法對owner進行了賦值,但AddRange方法沒有,而在帖子里所用的是AddRange方法,所以造成了這個問題。那為什么對Text賦值以后,子項里的內(nèi)容又能夠顯示了呢?好吧,再來看看ListViewItem.Text的源碼復(fù)制代碼 public string Text { get { if (SubItemCount == 0) { return string.Empty; } else { return subItems[0].Text; } } set { SubItems[0].Text = value; } }復(fù)制代碼對ListViewItem.Text的賦值實際上就是對它第0個子項的Text賦值,那為什么這個子項可以工作呢,好吧,再來看看第0個子項的來歷,以下是ListViewItem.SubItems的源碼。復(fù)制代碼 public ListViewSubItemCollection SubItems { get { if (SubItemCount == 0) { subItems = new ListViewSubItem[1]; subItems[0] = new ListViewSubItem(this, string.Empty); SubItemCount = 1; } if (listViewSubItemCollection == null) { listViewSubItemCollection = new ListViewSubItemCollection(this); } return listViewSubItemCollection; } }復(fù)制代碼由于帖子里使用了ListViewItem的無參數(shù)構(gòu)造函數(shù),因此在第一次調(diào)用SubItems屬性時,SubItemCount的值為0,這時就會自動插入一個子項,而這里使用的構(gòu)造函數(shù)直接把當(dāng)前ListViewItem傳進去了,子項的owner就有了值,因此可以正常顯示文字。回想前面的對子項Text賦值的源碼,在賦值以后會調(diào)用owner.UpdateSubItems(-1)來更新顯示,這個方法并不是僅僅更新一個子項,而是會更新所有子項,因此所有的內(nèi)容又都可以看到了。最后還有一個問題,為什么調(diào)用ListView.Refresh或Invalidate方法沒用呢?我沒有做深入研究,只是做一個猜想。因為.net的ListView控件只是對原生Windows的ListView控件的封裝,在OwnerDraw為false時,所有的繪圖都由原生的ListView控件完成。從以上代碼可以看出,子項的文本在托管代碼里保存了一份,而我敢肯定在原生的控件里也保存了一份,當(dāng)owner存在時,這兩個值是相同的,而在owner不存在時,由于沒有更新導(dǎo)致原生控件里沒有更新而失去了同步,這樣無論怎么Refresh都是沒有用的。Bug就分析到此,原因找到了,解決辦也自然有了。但我想說的不是解決辦法,而是怎么利用這個BUG,再來看看ListViewItem.UpdateSubItems方法。復(fù)制代碼 internal void UpdateSubItems(int index){ UpdateSubItems(index, SubItemCount); } internal void UpdateSubItems(int index, int oldCount){ if (listView != null && listView.IsHandleCreated) { int subItemCount = SubItemCount; int itemIndex = Index; if (index != -1) { listView.SetItemText(itemIndex, index, subItems[index].Text); } else { for(int i=0; i < subItemCount; i++) { listView.SetItemText(itemIndex, i, subItems[i].Text); } } for (int i = subItemCount; i < oldCount; i++) { listView.SetItemText(itemIndex, i, string.Empty); } } }復(fù)制代碼ListViewSubItem.set_Text在調(diào)用此方法時,專入的參數(shù)是-1,可以看出這將會導(dǎo)致所有的子項重繪,這點前面說過了。按此計算,如果ListView有10列,那每行需要重繪100次,其中有90次是在做無用功,不但增加了CPU的負(fù)擔(dān),還會可能會導(dǎo)致界面閃爍,但如果合理地利用這個BUG,可以有效改善這個情況。==補充======================================================做了一個實地測試,30列200行,做一次所有行和列的刷新,常規(guī)方法700ms,而利用這個BUG可以降到25ms。最后做個總結(jié)在為ListView添加行項目時,各項目的SubItem如果采用AddRange方法添加,會導(dǎo)致在后續(xù)更新SubItem的Text時,界面上不會更改,解決辦法有兩種:1、不要使用ListViewItem.SubItems.AddRange方法,而改用Add。2、仍舊使用AddRange方法,但在更新內(nèi)容時,第0列(也就是ListViewItem.Text)最后更新。但是這個BUG歪打正著地為提升ListView性能提供了可能,可使用上面的第2個解決辦法實現(xiàn),在大數(shù)量時效果尤其明顯。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 噜噜噜影院 | 国产91小视频在线观看 | 高清国产在线 | 免费毛片在线 | 成人三区四区 | 毛片视频观看 | 中文字幕天堂在线 | 欧美一级电影网 | 黄色网址免费在线 | 黄色毛片免费视频 | 久久久一区二区 | 国产一区亚洲 | 精品一区久久久 | 久久久久久久亚洲视频 | 欧美精品成人一区二区三区四区 | 99精品国产视频 | 免费一级在线观看 | 国产91一区 | a集毛片| 国产一区视频在线观看免费 | 久久精品久久精品国产大片 | 国产高潮好爽好大受不了了 | 国产免费一级淫片 | 成人综合免费视频 | 91精品国产福利尤物免费 | 欧美成人精品一区二区男人小说 | 国产精品成年片在线观看, 激情小说另类 | 精品中文字幕在线播放 | 中文字幕在线观看1 | 国产一区二区三区视频在线 | 舌头伸进添的我好爽高潮网站 | 国产成人高清在线观看 | 亚洲一区二区在线 | 亚洲免费视频大全 | 91精品国产综合久久青草 | 欧美国产一区二区三区 | 久久精品av | 欧美激情 在线播放 | 国产一级一片免费播放 | 欧美性受xxxx人人本视频 | hdbbwsexvideo |