轉(zhuǎn)帖|其它|編輯:郝浩|2010-12-27 14:04:32.000|閱讀 2358 次
概述:DataGrid 控件提供了一種靈活的方式來以行和列的形式顯示數(shù)據(jù)集合。但卻沒有提供增加、刪除行、即時輸入等功能,若要實(shí)現(xiàn)類似于Winform下的DataGrid批量錄入功能,還得做一些手腳,本文針對這幾個問題,提出一些解決思路。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
DataGrid 控件提供了一種靈活的方式來以行和列的形式顯示數(shù)據(jù)集合。但卻沒有提供增加、刪除行、即時輸入等功能,若要實(shí)現(xiàn)類似于Winform下的DataGrid批量錄入功能,還得做一些手腳:
1. 顯示行號;
2. 即時輸入;
3. 增加新行;
4. 刪除行;
5. 復(fù)制、粘貼行/多行
本文針對這幾個問題,提出一些解決思路。
1. 顯示行號
網(wǎng)上也有一些顯示行號的文章,但都是一個處理思路,就是在LoadingRow事件中做手腳,如這篇文章中所提供的思路《[Silverlight]奇技銀巧系列-4 在DataGrid中顯示行號》:
1: dataGrid1.LoadingRow += new EventHandler<DataGridRowEventArgs>(dataGrid1_LoadingRow);
2:
3: void dataGrid1_LoadingRow(object sender, DataGridRowEventArgs e) {
4: int index = e.Row.GetIndex();
5: var cell = dataGrid1.Columns[0].GetCellContent(e.Row) as TextBlock;
6: cell.Text = (index + 1).ToString();
7: }
SL幫助文檔中對LoadingRow的解釋是:"若要改進(jìn)性能,DataGrid 控件不針對綁定數(shù)據(jù)源中的每個數(shù)據(jù)項(xiàng)實(shí)例化 DataGridRow 對象。而是僅當(dāng)需要時才由數(shù)據(jù)網(wǎng)格創(chuàng)建 DataGridRow 對象,并盡量重復(fù)使用這些對象。例如,數(shù)據(jù)網(wǎng)格為當(dāng)前位于視圖中的每個數(shù)據(jù)項(xiàng)創(chuàng)建一個 DataGridRow 對象,并在行滾出視圖之外時回收它。"
這個處理思路的一個問題,就是當(dāng)DataGrid的行比較多,超出可視區(qū)域(出現(xiàn)滾動條)后;然后再刪除前面的行,行號就廢了。因?yàn)樘幱诳梢晠^(qū)域中的現(xiàn)有沒有被刪除的行,不會執(zhí)行LoadingRow事件,所以顯示的Index不會被更新。
處理思路:
我們一般是將ObservableCollection<Entity>作為DataGrid的數(shù)據(jù)源。一個變態(tài)的處理思路,就是給Entity增加一個Index屬性(修改時引發(fā)PropertyChanged事件),然后再DataGrid的LoadingRow/UnloadingRow中,取得DataGrid的數(shù)據(jù)源ObservableCollection<Entity>,然后更新每個Index的值。
不過這樣也有一個問題,就是在排序后,Index不會重新計算,顯得有點(diǎn)亂。不知道排序會引發(fā)啥事件,如果在排序事件中也來更新一次Index,就沒有問題了。哪位知道排序會引發(fā)啥事件,請告訴我,謝謝。/:)
2. 即時輸入
默認(rèn)情況下,DataGrid的Cell(TextBlock)不是出于編輯狀態(tài),要按F2或者鼠標(biāo)單擊,才能進(jìn)入編輯狀態(tài)(TextBox)。如果用鼠標(biāo)點(diǎn),或者每次都按F2,用起來非常不爽。
處理思路:
參考文章《An attempt to make the Silverlight DataGrid similar to Excel》,里面提出的思路就是在KeyDown\GotFocus\CellEditEnded三個事件中進(jìn)行處理:
(1) KeyDown事件中,捕捉按鍵,如果是字符鍵,則記錄到DataGrid.Tag中,然后執(zhí)行dataGrid.BeginEdit(),強(qiáng)制DataGrid進(jìn)入編輯狀態(tài)。
(2) GotFocus事件中,將DataGrid.Tag中記錄的字符取出來,然后付給輸入框(TextBox);
(3) CellEditEnded事件中,清理DataGrid.Tag。
在該文的回復(fù)中,有人提出了一個可替代的事件組合:TextInput/PreparingCellForEdit/KeyDown。也是一個處理思路。
3. 增加新行
貌似新版本的SL,可以支持增加新行了?!段④洶l(fā)布Silverlight 4新版并更新Silverlight Tools和SDK》,但問題是,找遍了網(wǎng)絡(luò),竟然沒有一個例子,M$的論壇上,也是只有提問沒有答案。。。所以還是得自己動手。
處理思路:
快捷鍵:DataGrid的KeyDown事件中,判斷按鍵;
增加新行:增加新行比較簡單,上面提到,DataGrid的數(shù)據(jù)源是ObservableCollection<Entity>,因此,只要我們向該集合中增加一個元素,就能達(dá)到增加新行的目的。
4. 刪除行
處理思路同增加新行:
快捷鍵:KeyDown中判斷按鍵;
刪除行:取得DataGrid的當(dāng)前選擇行dataGrid.SelectedItem as Entity,然后從將Entity從ObservableCollection<Entity>中刪除。
5. 復(fù)制/粘行
處理思路1:
《An attempt to make the Silverlight DataGrid similar to Excel》一文中,也提供了一個復(fù)制/粘貼的思路:
主要分三個步驟:
(1). 獲取DataGrid選擇行,然后將每個cell(TextBlock)的中的文本數(shù)據(jù),用"\t"分割,得到文本值;(如果Cell不在可視區(qū)域內(nèi),則調(diào)用dataGrid.ScrollIntoView,讓Cell顯示出來,然后才能取到TextBlock/TextBox)
(2). 將數(shù)據(jù)保存到系統(tǒng)的粘貼板:
1: var clipboardData = (ScriptObject)HtmlPage.Window.GetProperty("clipboardData");
2: clipboardData.Invoke("setData", "text", "格式化的自定義格式的數(shù)據(jù)");
(3). 從粘貼板上將數(shù)據(jù)取回來,再賦值給目標(biāo)行中的Cell(TextBox):
1: var clipboardData = (ScriptObject)HtmlPage.Window.GetProperty("clipboardData");
2: string textData = clipboardData.Invoke("getData", "text").ToString();
但該文章中,只提供了單行復(fù)制/粘貼的功能;而且這段代碼有很大局限性,只能在IE中運(yùn)行。
處理思路2:
上面的復(fù)制/粘貼功能,只局限在IE中運(yùn)行。另一個處理思路,可以做兩點(diǎn)改進(jìn):
(1) 上面提到,DataGrid的數(shù)據(jù)源是ObservableCollection<T>,只要改變該集合中的值,SL就會自動刷新DataGrid。因此我們可以不用去操作DataGrid中的Cell,而是直接操作ObservableCollection<T>??截惖臅r候,對選中的一個或多個元素(Entity)執(zhí)行xml序列化得到文本值;粘貼的時候,將文本值反序列化回來,然后對掉選中的元素(Entity)逐個屬性賦值。
從ObservableCollection<T>得到文本值由兩個處理思路:可以按上面描述的序列化來處理;也可以按處理思路1種的文本拼接思路,按照csv格式來進(jìn)行拼接:屬性值之間以"\t"分隔,元素(Entity)之間以"\r\n"分隔。
按csv格式拼接的好處,就是拷貝的數(shù)據(jù),可以直接粘貼到Excel中。而序列化的好處,就是可以保證兼容性;譬如批量錄入過程耗時可能比較長,中途可能需要跳轉(zhuǎn)到其他頁面、或者離開很久、或者下班關(guān)機(jī),那前面錄入的相當(dāng)于白干了;因此需要在客戶端提供了一個臨時保存的功能:把當(dāng)前數(shù)據(jù)保存到文件(SL4支持將數(shù)據(jù)保存獨(dú)立存儲區(qū)中),下次再從文件中把數(shù)據(jù)加載出來;但如果中途系統(tǒng)升級了,增加或者減少了一個字段/列,則序列化可以忽略增加/減少的列,繼續(xù)正常工作。但CSV格式拼接出來的文本,缺少列描述信息,就掛了。
(2) 用一個TextBox做中轉(zhuǎn)。將文本值賦值給中轉(zhuǎn)的TextBox,然后對TextBox按Ctrl+C,從而將數(shù)據(jù)拷貝到系統(tǒng)的粘貼板;粘貼的過程正好反過來,先將系統(tǒng)粘貼板的數(shù)據(jù),粘貼到中轉(zhuǎn)用的TextBox,然后再取得TextBox中的值。
整個處理過程如下圖所示:
在復(fù)制/粘貼的過程中,可能還會遇到一種情況,即選擇了DataGrid中的N行,然后復(fù)制;但粘貼的時候,可能會選擇M行,有三種情況需要考慮:
(1) M=N:這種情況下,正好元素可以一一匹配上;逐個元素按屬性賦值就行;
(2) M>N:雖然粘貼時,選擇的行數(shù)更多,但我們可以忽略多出的行(M-N),只處理前面的N行;
(3) M<N:此時,需要考慮多出的復(fù)制行(N-M)要怎么處理了;有三種處理辦法:(1) 忽略多出的復(fù)制行;(2) 按照Excel的處理思路,只允許粘貼到連續(xù)的N行中;(3) 我的處理思路是,可以跨行粘貼,對于多出的行,可以插入到ObservableCollection<T>中。
6. 類圖結(jié)構(gòu)
7. 使用方法
1: dataGrid.UseExtender<Employee>();
這是最簡單的情況,只提供基本的即時輸入、增加、刪除、復(fù)制、粘貼功能等;一個稍微復(fù)雜點(diǎn)的調(diào)用方式如下:
1: //happyhippy.cnblogs.com
2: //方法定義原型
3: public static void UseExtender<T>(this DataGrid dataGrid, string autoIncreaseField = "",
4: bool useXmlCopy = true, Action<DataGrid, EntityChangedEventArgs> rowsChanged = null,
5: bool addable = true, bool deleteable = true)
6: where T : class, new()
7:
8: //調(diào)用:
9: dataGrid.UseExtender<Employee>("Index", true,
10: (s, eventArg) =>
11: {
12: //取得剛操作(插入/刪除)的元素集合,可以干一些后續(xù)的事情。。。
13: IList<Employee> changedEntities = eventArg.ChangedEntities as IList<Employee>;
14: }, true, true);
運(yùn)行效果:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:慧都控件網(wǎng)