問題描述:在WinForm中如何同步滾動兩個DataGrid。
問題分析:拿到這個首先想到的就是重寫Scroll方法,可是想想工作量有些大,所以想在Form級別上做做手腳,可是屢試不成功(在網上聽說有實現的不過沒有見到)。無奈之下只好看看能不能從DataGrid下手,看看DataGrid的成員列表可以看到這樣兩個保護性的方法:
GridHScrolled Listens for the horizontal scrollbar's scroll event.
GridVScrolled Listens for the vertical scrollbar's scroll event.
很顯然這個兩個監聽滾動條事件的方法,要得就是它,微軟真是太好了(心中暗喜)。好了那現在就開始些我們自己的DataGrid吧。首先需要創建一個解決方案,其中有兩個工程,一個Windows控件庫項目和WinForm項目,前者是我們的寫的DataGrid控件後者則是測試控件的工程。創建Windows用戶空間會有一個默認的類,刪了或者修改他的名字為crlDataGrid(你自己隨便叫好了)。我們修改它的繼承關系,讓他從DataGrid繼承。如下所示:
public class CrlDataGrid : System.Windows.Forms.DataGrid。
這樣我們就可以用我們自己的DataGrid公開上面提到的兩個方法了。如下所示:
public void crlGridVScrolled(object sender,ScrollEventArgs e){
this.GridVScrolled(sender,e);
}
public void crlGridHScrolled(object sender,ScrollEventArgs e){
this.GridHScrolled(sender,e);
}
到此,我們的控件就完成了。其實很簡單就是公開了那兩個原來隱藏的方法。
接下來就是測試項目:我們新建一個WinForm工程。首先我們需要引用我們自己的DataGrid控件,方法如下:在工具箱裡使用鼠標右鍵選擇添加/移除項,使用浏覽找到我們剛才工程所在目錄下面的dll之後添加到工具箱裡。用如下的方法把數據綁定到我們自定義個DataGrid上面:
SqlConnection conn = new SqlConnection("server=192.192.192.1;database=northwind;uid=sa;pwd=;");
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Orders",conn);
DataSet ds = new DataSet();
da.Fill(ds);
this. grdSource.DataSource = ds.Tables[0].DefaultView;
this. grdAim.DataSource = ds.Tables[0].DefaultView;
其中grdSource和grdAim是兩個自定義DataGrid,我們要做的就是當第一個DataGrid(grdSource)滾動的時候第二個也以相同的方式滾動。
private CrlDataGrid.CrlDataGrid grdSource;
private CrlDataGrid.CrlDataGrid grdAim;
下面我們要做的是實現垂直方向的同步我們申明兩個VscrollBar對象,為了也可以橫向的拖動,我們還聲明兩個水平的滾動條對象。
VScrollBar m_SourceVScroll;
VScrollBar m_AimVScroll;
HScrollBar m_AimHScroll;
HScrollBar m_SourceHScroll;
我們將在兩個自定義DataGrid中找到他們對應的滾動條對象,同時給這些滾動條的事件壓入堆中,同時為他們添加事件處理程序,代碼如下:
public void addEventHandler(){
foreach(Control ctrl in this.grdSource.Controls){
if(ctrl.GetType().Name == "VScrollBar"){
this.m_SourceVScroll = (VScrollBar)ctrl;
break;
}
}
foreach(Control ctrl in this.grdAim.Controls){
if(ctrl.GetType().Name == "VScrollBar"){
this.m_AimVScroll = (VScrollBar)ctrl;
break;
}
}
this.m_SourceVScroll.Scroll +=new ScrollEventHandler(m_SourceVScroll_Scroll);
this.m_AimVScroll.Scroll +=new ScrollEventHandler(m_AimVScroll_Scroll);
//================== 添加水平 ======================
foreach(Control ctrl in this.grdSource.Controls){
if(ctrl.GetType().Name == "HScrollBar"){
this.m_SourceHScroll = (HScrollBar)ctrl;
break;
}
}
foreach(Control ctrl in this.grdAim.Controls){
if(ctrl.GetType().Name == "HScrollBar"){
this.m_AimHScroll = (HScrollBar)ctrl;
break;
}
}
this.m_AimHScroll.Scroll +=new ScrollEventHandler(m_AimHScroll_Scroll);
this.m_SourceHScroll.Scroll +=new ScrollEventHandler(m_SourceHScroll_Scroll);
}
接下來我們要在構造函數中調用這個方法如下所示:
public Form1(){
//
// Windows 窗體設計器支持所必需的
//
InitializeComponent();
this.addEventHandler();
}
最後就是添加事件處理函數如下所示:
private void m_SourceVScroll_Scroll(object sender, ScrollEventArgs e) {
this.m_AimVScroll.Value = this.m_SourceVScroll.Value;
this.grdAim.crlGridVScrolled(sender,e);
}
private void m_AimVScroll_Scroll(object sender, ScrollEventArgs e) {
this.m_SourceVScroll.Value = this.m_AimVScroll.Value;
this.grdSource.crlGridVScrolled(sender,e);
}
private void m_AimHScroll_Scroll(object sender, ScrollEventArgs e) {
this.m_SourceHScroll.Value = this.m_AimHScroll.Value;
this.grdSource.crlGridHScrolled(sender,e);
}
private void m_SourceHScroll_Scroll(object sender, ScrollEventArgs e) {
this.m_AimHScroll.Value = this.m_SourceHScroll.Value;
this.grdAim.crlGridHScrolled(sender,e);
}
上面分別是水平滾動和垂直滾動的事件處理程序。