สำหรับเว็บแอปพลิเคชันการนำเสนอข้อมูลเกือบทั้งหมด การจัดการวิธีการแสดงข้อมูลและการหลีกเลี่ยงความรู้สึกสับสนต่อผู้ใช้ถือเป็นหนึ่งในเป้าหมายหลัก การแสดง 20 บันทึกต่อหน้าเป็นสิ่งที่ยอมรับได้อย่างแน่นอน แต่การแสดง 10,000 รายการต่อหน้าอาจทำให้ผู้ใช้ไม่สะดวกได้อย่างง่ายดาย การแบ่งข้อมูลออกเป็นหลายๆ หน้าเพื่อแสดง ซึ่งก็คือการแบ่งหน้าข้อมูล เป็นวิธีที่พบได้บ่อยที่สุดในการแก้ปัญหาดังกล่าว
1. ภาพรวม
ASP.NET เองมีตัวควบคุมเดียวที่สนับสนุนการเพจข้อมูล นั่นคือตัวควบคุมการเพจ DataGrid อย่างไรก็ตาม มันเหมาะสำหรับใช้ในสภาพแวดล้อมอินทราเน็ตมากกว่า สำหรับสภาพแวดล้อมอินเทอร์เน็ต ดูเหมือนว่าฟังก์ชันที่ได้รับจากการควบคุมเพจของ DataGrid ก็เพียงพอที่จะสร้างเว็บแอปพลิเคชันที่ยืดหยุ่นได้ สาเหตุหนึ่งก็คือ การควบคุม DataGrid กำหนดข้อจำกัดเกี่ยวกับตำแหน่งที่นักออกแบบเว็บสามารถวางตัวควบคุมเพจและลักษณะที่ปรากฏของตัวควบคุมเพจได้ ตัวอย่างเช่น ตัวควบคุม DataGrid ไม่อนุญาตให้มีการวางตำแหน่งตัวควบคุมเพจในแนวตั้ง การควบคุมอื่นที่สามารถใช้ประโยชน์จากเทคโนโลยีเพจจิ้งได้คือนักพัฒนาเว็บ Repeater สามารถใช้การควบคุม Repeater เพื่อกำหนดค่าวิธีการแสดงข้อมูลได้อย่างรวดเร็ว แต่ฟังก์ชันเพจจิ้งต้องการให้นักพัฒนาใช้งานด้วยตนเอง แหล่งข้อมูลมีการเปลี่ยนแปลงอยู่ตลอดเวลา และวิธีการนำเสนอข้อมูลจะแตกต่างกันไปอย่างมาก เห็นได้ชัดว่าเป็นการเสียเวลาในการปรับแต่งการควบคุมเพจสำหรับเงื่อนไขที่เปลี่ยนแปลงเหล่านี้ การสร้างการควบคุมเพจสากลที่ไม่จำกัดเฉพาะการควบคุมการนำเสนอที่เฉพาะเจาะจงจะช่วยประหยัดเวลาได้อย่างมาก
การควบคุมข้อมูลสากลที่ยอดเยี่ยมไม่เพียงแต่มีฟังก์ชันการเพจปกติเท่านั้น แต่ยังสามารถ:
⑴ มีปุ่มนำทางเพจ "หน้าแรก", "หน้าก่อนหน้า", "หน้าถัดไป" และ "หน้าสุดท้าย"
⑵ ปรับสถานะตามสถานการณ์การแสดงข้อมูล นั่นคือ มีความไวของข้อมูล หากตั้งค่าการควบคุมเพจให้แสดง 10 เรคคอร์ดต่อหน้า แต่จริงๆ แล้วมีเพียง 9 เรคคอร์ด ก็ไม่ควรแสดงการควบคุมเพจ เมื่อข้อมูลถูกแบ่งออกเป็นหลายเพจสำหรับแสดง "หน้าแรก" และ "ด้านบน" ของ หน้าแรก ไม่ควรแสดงปุ่ม "หน้า" และไม่ควรแสดงปุ่ม "หน้าถัดไป" และ "หน้าสุดท้าย" ของหน้าสุดท้าย
⑶ ไม่สามารถพึ่งพาการควบคุมการแสดงข้อมูลที่เฉพาะเจาะจงได้
⑷ ความสามารถในการปรับให้เข้ากับแหล่งข้อมูลต่างๆ ที่มีอยู่และในอนาคต
⑸ โหมดการแสดงผลควรกำหนดค่าได้ง่ายและรวมเข้ากับแอปพลิเคชันต่างๆ ได้อย่างง่ายดาย
⑹ เมื่อเพจพร้อม ให้เตือนการควบคุมอื่นๆ
⑺ แม้แต่นักออกแบบเว็บไซต์ที่ไม่มีประสบการณ์ก็สามารถใช้งานได้โดยไม่ยาก
⑻ ระบุข้อมูลแอตทริบิวต์เกี่ยวกับข้อมูลเพจ
ขณะนี้มีการควบคุมเชิงพาณิชย์ในตลาดที่มีฟังก์ชันข้างต้น แต่ทั้งหมดมีราคาแพง สำหรับนักพัฒนาจำนวนมาก การสร้างการควบคุมเพจแบบสากลด้วยตัวเองคือตัวเลือกที่เหมาะสมที่สุด
รูปที่ 1 แสดงอินเทอร์เฟซการรันของตัวควบคุมเพจสากลในบทความนี้ ซึ่งตัวควบคุมที่ใช้สำหรับการแสดงผลคือตัวควบคุม Repeater การควบคุมเพจประกอบด้วยส่วนประกอบสองประเภท: ปุ่มนำทางสี่ปุ่ม และชุดลิงก์หมายเลขหน้า
ผู้ใช้สามารถเปลี่ยนตัวควบคุมการแสดงผลและเปลี่ยนลักษณะที่ปรากฏของตัวควบคุมเพจได้อย่างง่ายดาย ตัวอย่างเช่น ตัวควบคุมการแสดงผลที่ทำงานร่วมกับตัวควบคุมเพจจะถูกแทนที่ด้วยตัวควบคุม DataGrid และลิงก์หมายเลขหน้าและปุ่มนำทางสี่ปุ่มจะแสดงเป็นสองแถว
ASP.NET สนับสนุนสามวิธีในการสร้างตัวควบคุมเว็บแบบกำหนดเอง: ตัวควบคุมผู้ใช้ ตัวควบคุมแบบผสม และตัวควบคุมแบบกำหนดเอง ชื่อของตัวควบคุมชนิดที่สาม ตัวควบคุมแบบกำหนดเอง อาจทำให้เข้าใจผิดได้ง่าย ที่จริงแล้ว การควบคุมทั้งสามควรได้รับการพิจารณาว่าเป็นการควบคุมแบบกำหนดเอง ความแตกต่างระหว่างตัวควบคุมแบบผสมและตัวควบคุมแบบกำหนดเองของ Microsoft คือ ก่อนหน้านี้ต้องใช้เมธอด CreateChildControls() เมธอด CreateChildControls() อนุญาตให้ตัวควบคุมวาดตัวเองใหม่ตามเหตุการณ์บางอย่าง สำหรับเพจเจอร์สากลของบทความนี้ เราจะใช้ตัวควบคุมแบบผสม
ไดอะแกรมลำดับ UML ต่อไปนี้แสดงกลไกทั่วไปของการควบคุมเพจสากล
แม้ว่าเป้าหมายของเราคือการทำให้การควบคุมเพจสากลเป็นอิสระจากการควบคุมที่แสดงถึงข้อมูล แต่ก็เห็นได้ชัดว่าต้องมีวิธีบางอย่างสำหรับการควบคุมเพจเพื่อเข้าถึงข้อมูล การควบคุมทุกอย่างที่สืบทอดมาจากคลาสการควบคุมจะจัดให้มีเหตุการณ์ DataBinding เราลงทะเบียนเพจเจอร์เองในฐานะ Listener สำหรับเหตุการณ์ DataBinding เพื่อให้เพจเจอร์สามารถเรียนรู้เกี่ยวกับข้อมูลและแก้ไขข้อมูลได้ เนื่องจากการควบคุมทั้งหมดที่สืบทอดมาจากคลาส Control มีเหตุการณ์ DataBinding นี้ การควบคุมเพจเจอร์จึงบรรลุเป้าหมายที่ไม่ต้องพึ่งพาการควบคุมการนำเสนอข้อมูลเฉพาะ กล่าวอีกนัยหนึ่ง การควบคุมเพจเจอร์สามารถเชื่อมโยงกับการควบคุมทั้งหมดที่ได้มาจากคลาส Control นั่นคือสามารถเชื่อมโยงกับส่วนควบคุมเว็บเกือบทั้งหมดได้
2. ฟังก์ชันหลัก
เมื่อตัวควบคุมการนำเสนอทริกเกอร์เหตุการณ์ DataBinding ตัวควบคุมเพจสามารถรับคุณสมบัติ DataSource น่าเสียดายที่ Microsoft ไม่มีอินเทอร์เฟซที่คลาสการเชื่อมโยงข้อมูลทั้งหมดใช้งาน เช่น IdataSourceProvider และไม่ใช่ตัวควบคุมทั้งหมดที่สืบทอดจากคลาส Control หรือ WebControl ที่มีคุณสมบัติ DataSource ดังนั้นจึงไม่มีประเด็นในการอัปแคสต์ไปยังคลาส Control ซึ่งเป็นสิ่งเดียวที่เป็นไปได้ วิธีคือการดำเนินการคุณสมบัติ DataSoruce โดยตรงผ่าน Reflection API ก่อนที่จะหารือเกี่ยวกับวิธีการจัดการเหตุการณ์ ควรสังเกตว่าในการลงทะเบียนตัวจัดการเหตุการณ์ คุณต้องได้รับการอ้างอิงถึงตัวควบคุมการนำเสนอก่อน การควบคุมเพจแสดงคุณสมบัติสตริงอย่างง่าย BindToControl:
BindToControl สตริงสาธารณะ
-
รับ
-
ถ้า (_bindcontrol == null)
โยน NullReferenceException ใหม่ ("ก่อนที่จะใช้ตัวควบคุมการเพจ โปรดผูกเข้ากับตัวควบคุมโดยการตั้งค่าคุณสมบัติ BindToControl");
กลับ _bindcontrol;}
ตั้งค่า {_bindcontrol = ค่า;}
}
วิธีการนี้มีความสำคัญมาก ดังนั้นจึงเป็นการดีที่สุดที่จะส่งข้อความที่ชัดเจนยิ่งขึ้น แทนที่จะทิ้ง NullReferenceException มาตรฐาน ในวิธีการ OnInit ของตัวควบคุมเพจ เราจะแก้ไขการอ้างอิงไปยังตัวควบคุมการนำเสนอ ตัวอย่างนี้ควรใช้ตัวจัดการเหตุการณ์ OnInit (แทนที่จะเป็นตัวสร้าง) เพื่อให้แน่ใจว่าเพจ aspx ที่คอมไพล์ด้วย JIT มีชุด BindToControl
การป้องกันการแทนที่เป็นโมฆะ OnInit (EventArgs e)
-
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += ตัวจัดการเหตุการณ์ใหม่ (BoundControl_DataBound);
ฐาน OnInit(e);
-
}
การดำเนินการค้นหาตัวควบคุมการนำเสนอจะเสร็จสิ้นโดยการค้นหาตัวควบคุมหลักของตัวควบคุมเพจ ในที่นี้ เพจคือตัวมันเอง การใช้พาเรนต์ในลักษณะนี้เป็นอันตราย ตัวอย่างเช่น ถ้าคอนโทรลเพจถูกฝังอยู่ในคอนโทรลอื่น เช่น คอนโทรลตาราง การอ้างอิงพาเรนต์จะเป็นการอ้างอิงถึงคอนโทรลตารางจริงๆ เนื่องจากวิธีการ FindControl ค้นหาเฉพาะคอลเลกชันการควบคุมปัจจุบัน จึงไม่สามารถค้นหาได้เว้นแต่ว่าการควบคุมการนำเสนอจะอยู่ในคอลเลกชัน วิธีที่ปลอดภัยกว่าคือการค้นหาซ้ำผ่านคอลเลกชันของตัวควบคุมจนกว่าจะพบตัวควบคุมเป้าหมาย
หลังจากค้นหา BoundControl แล้ว เราจะลงทะเบียนการควบคุมเพจในฐานะ Listener สำหรับเหตุการณ์ DataBinding เนื่องจากการควบคุมเพจดำเนินการบนแหล่งข้อมูล จึงเป็นสิ่งสำคัญที่ตัวจัดการเหตุการณ์นี้เป็นอันสุดท้ายในสายโซ่การโทร อย่างไรก็ตาม ตราบใดที่ตัวควบคุมการนำเสนอลงทะเบียนตัวจัดการเหตุการณ์ DataBinding ในตัวจัดการเหตุการณ์ OnInit (ลักษณะการทำงานเริ่มต้น) จะไม่มีปัญหาเมื่อตัวควบคุมเพจดำเนินการแหล่งข้อมูล
ตัวจัดการเหตุการณ์ DataBound มีหน้าที่รับผิดชอบในการรับคุณสมบัติ DataSource ของตัวควบคุมการนำเสนอ
โมฆะส่วนตัว BoundControl_DataBound (ผู้ส่งวัตถุ System.EventArgs e)
-
ถ้า (HasParentControlCalledDataBinding) กลับมา;
ประเภทประเภท = sender.GetType();
_datasource = type.GetProperty("แหล่งข้อมูล");
ถ้า (_แหล่งข้อมูล == null)
Throw new NotSupportedException("ตัวควบคุมเพจต้องการให้ตัวควบคุมการนำเสนอต้องมีแหล่งข้อมูล");
ข้อมูลวัตถุ = _datasource.GetGetMethod().เรียก(ผู้ส่ง,null);
_builder = อะแดปเตอร์ [data.GetType()];
ถ้า (_builder == null)
Throw new NullReferenceException("ไม่ได้ติดตั้งอะแดปเตอร์ที่เหมาะสมเพื่อจัดการกับประเภทแหล่งข้อมูลต่อไปนี้: "+data.GetType());
_builder.Source = ข้อมูล;
ApplyDataSensitivityRules();
BindParent();
RaiseEvent (DataUpdate นี้);
-
ใน DataBound เราพยายามรับคุณสมบัติ DataSource ผ่าน Reflection API จากนั้นส่งคืนการอ้างอิงไปยังแหล่งข้อมูลจริง เมื่อทราบแหล่งข้อมูลแล้ว ตัวควบคุมการเพจจะต้องทราบวิธีดำเนินการกับแหล่งข้อมูลด้วย เพื่อให้การควบคุมเพจไม่ขึ้นอยู่กับการควบคุมการนำเสนอเฉพาะ ปัญหาจะซับซ้อนมากขึ้น อย่างไรก็ตาม การทำให้การควบคุมเพจขึ้นอยู่กับแหล่งข้อมูลเฉพาะ เอาชนะเป้าหมายของการออกแบบการควบคุมเพจที่ยืดหยุ่น เราจำเป็นต้องใช้สถาปัตยกรรมปลั๊กอินเพื่อให้แน่ใจว่าการควบคุมเพจสามารถจัดการแหล่งข้อมูลต่างๆ ได้ ไม่ว่าจะเป็นแหล่งข้อมูลที่ .NET ให้ไว้หรือแหล่งข้อมูลที่กำหนดเอง
เพื่อมอบสถาปัตยกรรมแบบเสียบปลั๊กที่แข็งแกร่งและปรับขนาดได้ เราจะสร้างโซลูชันโดยใช้รูปแบบตัวสร้าง [GoF]
รูปที่ 4
อินเทอร์เฟซ IDataSourceAdapter กำหนดองค์ประกอบพื้นฐานที่สุดที่จำเป็นสำหรับการควบคุมเพจเพื่อดำเนินการข้อมูล ซึ่งเทียบเท่ากับ "ปลั๊ก"
อินเทอร์เฟซสาธารณะ IDataSourceAdapter
-
int TotalCount{ได้รับ;}
วัตถุ GetPagedData (int เริ่มต้น, int end);
}
คุณสมบัติ TotalCount ส่งคืนจำนวนองค์ประกอบทั้งหมดที่มีอยู่ในแหล่งข้อมูลก่อนประมวลผลข้อมูล ในขณะที่เมธอด GetPagedData ส่งคืนชุดย่อยของข้อมูลดั้งเดิม ตัวอย่างเช่น สมมติว่าแหล่งข้อมูลเป็นอาร์เรย์ที่มี 20 องค์ประกอบ ตัวควบคุมเพจจิ้งจะแสดง ข้อมูลเป็น 10 องค์ประกอบต่อหน้า องค์ประกอบย่อยขององค์ประกอบในหน้าแรกคือองค์ประกอบอาร์เรย์ 0-9 และชุดย่อยขององค์ประกอบในหน้าที่สองคือองค์ประกอบอาร์เรย์ 10-19 DataViewAdapter จัดเตรียมปลั๊กประเภท DataView:
คลาสภายใน DataViewAdapter:IDataSourceAdapter
-
DataView ส่วนตัว _view;
DataViewAdapter ภายใน (มุมมอง DataView)
-
_view = ดู;
-
มหาชน int TotalCount
-
รับ {return (_view == null) ? 0 : _view.Table.Rows.Count;}
-
วัตถุสาธารณะ GetPagedData (int start, int end)
-
ตาราง DataTable = _view.Table.Clone();
สำหรับ (int i = start;i<=end && i<= TotalCount;i++)
-
table.ImportRow(_view[i-1].Row);
-
โต๊ะขากลับ;
-
}
DataViewAdapter ใช้วิธีการ GetPagedData ของ IDataSourceAdapter ซึ่งจะโคลน DataTable ดั้งเดิมและนำเข้าข้อมูลใน DataTable ดั้งเดิมลงใน DataTable ใหม่ การมองเห็นของคลาสนี้ถูกกำหนดไว้เป็นการภายในโดยเจตนาเพื่อซ่อนรายละเอียดการใช้งานจากนักพัฒนาเว็บ และมอบอินเทอร์เฟซที่ง่ายขึ้นผ่านคลาส Builder
AdapterBuilder คลาสนามธรรมสาธารณะ
-
วัตถุส่วนตัว _source;
CheckForNull() เป็นโมฆะส่วนตัว
-
ถ้า (_source == null) โยน NullReferenceException ใหม่ ("ต้องระบุแหล่งข้อมูลทางกฎหมาย");
-
แหล่งที่มาของวัตถุเสมือนสาธารณะ
-
รับ
-
CheckForNull();
กลับ _source;}
ชุด
-
_source = ค่า;
CheckForNull();
-
-
อะแดปเตอร์ IDataSourceAdapter นามธรรมสาธารณะ {get;}
}
คลาสนามธรรมของ AdapterBuilder มอบอินเทอร์เฟซที่สามารถจัดการได้มากขึ้นสำหรับประเภท IdataSourceAdapter เนื่องจากระดับนามธรรมที่เพิ่มขึ้น เราจึงไม่จำเป็นต้องใช้ IdataSourceAdapter โดยตรงอีกต่อไป ในเวลาเดียวกัน AdapterBuilder ยังให้คำแนะนำในการดำเนินการล่วงหน้าก่อนการเพจข้อมูลอีกด้วย นอกจากนี้ ตัวสร้างนี้ยังทำให้คลาสการใช้งานจริง เช่น DataViewAdapter โปร่งใสสำหรับผู้ใช้การควบคุมเพจ:
คลาสสาธารณะ DataTableAdapterBuilder:AdapterBuilder
-
DataViewAdapter ส่วนตัว _adapter;
DataViewAdapter ViewAdapter ส่วนตัว
-
รับ
-
ถ้า (_adapter == null)
-
ตาราง DataTable = (DataTable) แหล่งที่มา;
_adapter = DataViewAdapter ใหม่ (table.DefaultView);
-
กลับ _อะแดปเตอร์;
-
-
แทนที่สาธารณะ IDataSourceAdapter Adapter
-
รับ
-
กลับ ViewAdapter;
-
-
-
DataViewAdapterBuilder คลาสสาธารณะ: AdapterBuilder
-
DataViewAdapter ส่วนตัว _adapter;
DataViewAdapter ViewAdapter ส่วนตัว
-
รับ
{ // การสร้างอินสแตนซ์ล่าช้า
ถ้า (_adapter == null)
-
_adapter = DataViewAdapter ใหม่ ((DataView) แหล่งที่มา);
-
กลับ _อะแดปเตอร์;
-
-
แทนที่สาธารณะ IDataSourceAdapter Adapter
-
รับ {ส่งคืน ViewAdapter;}
-
}
ประเภท DataView และประเภท DataTable มีความสัมพันธ์กันอย่างใกล้ชิดจนอาจเหมาะสมที่จะสร้าง DataAdapter ทั่วไป จริงๆ แล้ว เพียงแค่เพิ่มตัวสร้างอื่นที่จัดการ DataTable ก็เพียงพอแล้ว น่าเสียดาย เมื่อผู้ใช้ต้องการฟังก์ชันการทำงานที่แตกต่างกันเพื่อจัดการกับ DataTable คลาสทั้งหมดจะต้องถูกแทนที่หรือสืบทอด หากเราสร้าง Builder ใหม่ที่ใช้ IdataSourceAdapter เดียวกัน ผู้ใช้จะมีอิสระมากขึ้นในการเลือกวิธีใช้งานอะแดปเตอร์
ในการควบคุมเพจ การดำเนินการค้นหาคลาส Builder ที่เหมาะสมจะเสร็จสมบูรณ์โดยคอลเล็กชันประเภทที่ปลอดภัย
AdapterCollection ระดับสาธารณะ: DictionaryBase
-
สตริงส่วนตัว GetKey (คีย์ประเภท)
-
ส่งคืนคีย์ชื่อเต็ม;
-
AdapterCollection สาธารณะ () {}
publicvoid เพิ่ม (คีย์ประเภท, ค่า AdapterBuilder)
-
Dictionary.Add(GetKey(คีย์),ค่า);
-
publicbool ประกอบด้วย (คีย์ประเภท)
-
กลับ Dictionary.Contains (GetKey (คีย์));
-
publicvoid ลบ (พิมพ์คีย์)
-
Dictionary.Remove(GetKey(คีย์));
-
AdapterBuilder สาธารณะนี้ [คีย์ประเภท]
-
รับ {return (AdapterBuilder) พจนานุกรม [GetKey (คีย์)];}
ชุด {พจนานุกรม [GetKey (คีย์)] = ค่า;}
-
}
AdapterCollection อาศัยประเภท DataSource และ DataSource ได้รับการแนะนำอย่างชาญฉลาดผ่าน BoundControl_DataBound คีย์ดัชนีที่ใช้ในที่นี้คือเมธอด Type.FullName ซึ่งช่วยให้มั่นใจถึงความเป็นเอกลักษณ์ของคีย์ดัชนีของแต่ละประเภท ในเวลาเดียวกัน ยังมอบหมายความรับผิดชอบในการตรวจสอบให้แน่ใจว่ามี Builder เพียงตัวเดียวสำหรับแต่ละประเภทให้กับ AdapterCollection เพิ่มการค้นหา Builder ให้กับเมธอด BoundControl_DataBound และผลลัพธ์จะเป็นดังนี้:
อะแดปเตอร์ AdapterCollection สาธารณะ
-
รับ {ส่งคืน _adapters;}
}
บูลส่วนตัว HasParentControlCalledDataBinding
-
รับ {return _builder != null;}
}
ส่วนตัวเป็นโมฆะ BoundControl_DataBound (ผู้ส่งวัตถุ System.EventArgs e)
-
ถ้า (HasParentControlCalledDataBinding) กลับมา;
ประเภทประเภท = sender.GetType();
_datasource = type.GetProperty("แหล่งข้อมูล");
ถ้า (_แหล่งข้อมูล == null)
Throw new NotSupportedException("ตัวควบคุมเพจต้องการให้ตัวควบคุมการนำเสนอต้องมีแหล่งข้อมูล");
ข้อมูลวัตถุ = _datasource.GetGetMethod().เรียก(ผู้ส่ง,null);
_builder = อะแดปเตอร์ [data.GetType()];
ถ้า (_builder == null)
Throw new NullReferenceException("ไม่ได้ติดตั้งอะแดปเตอร์ที่เหมาะสมเพื่อจัดการกับประเภทแหล่งข้อมูลต่อไปนี้: "+data.GetType());
_builder.Source = ข้อมูล;
ApplyDataSensitivityRules();
BindParent();
RaiseEvent (DataUpdate นี้);
}
วิธีการ BoundControl_DataBound ใช้ HasParentControlCalledDataBinding เพื่อตรวจสอบว่า Builder ถูกสร้างขึ้นหรือไม่ หากเป็นเช่นนั้น จะไม่ดำเนินการค้นหา Builder ที่เหมาะสมอีกต่อไป การเริ่มต้นของตาราง Adapters เสร็จสิ้นในตัวสร้าง:
public Pager()
-
SelectedPager=ใหม่ System.Web.UI.WebControls.Style();
UnselectedPager = System.Web.UI.WebControls.Style(); ใหม่
_adapters = AdapterCollection ใหม่ ();
_adapters.Add(typeof(DataTable),DataTableAdapterBuilder() ใหม่);
_adapters.Add(typeof(DataView),DataViewAdapterBuilder() ใหม่);
}
วิธีสุดท้ายที่จะนำไปใช้คือ BindParent ซึ่งใช้ในการประมวลผลและส่งคืนข้อมูล
BindParent เป็นโมฆะส่วนตัว ()
-
_datasource.GetSetMethod().วิงวอน(BoundControl,
วัตถุใหม่ []{_builder.Adapter.GetPagedData(StartRow,ResultsToShow*CurrentPage)});
}
วิธีนี้ง่ายมาก เนื่องจากจริงๆ แล้วการประมวลผลข้อมูลทำได้โดยอะแดปเตอร์ หลังจากกระบวนการนี้เสร็จสิ้น เราจะใช้ Reflection API อีกครั้ง แต่คราวนี้จะตั้งค่าคุณสมบัติแหล่งข้อมูลของตัวควบคุมการนำเสนอ
3. การออกแบบอินเทอร์เฟซ
จนถึงขณะนี้ ฟังก์ชันหลักของการควบคุมเพจได้ถูกนำมาใช้เกือบหมดแล้ว แต่หากไม่มีวิธีการนำเสนอที่เหมาะสม การควบคุมเพจจะไม่มีประโยชน์มากนัก
เพื่อแยกวิธีการนำเสนอออกจากตรรกะของโปรแกรมอย่างมีประสิทธิภาพ วิธีที่ดีที่สุดคือการใช้เทมเพลต หรือเพื่อให้เฉพาะเจาะจงมากขึ้น ให้ใช้อินเทอร์เฟซ Itemplate ในความเป็นจริง Microsoft เข้าใจถึงพลังของเทมเพลตอย่างชัดเจนและนำไปใช้เกือบทุกที่แม้แต่ในตัวแยกวิเคราะห์หน้าก็ตาม น่าเสียดายที่เทมเพลตไม่ใช่แนวคิดง่ายๆ อย่างที่บางคนคิด และต้องใช้เวลาพอสมควรกว่าจะเข้าใจสาระสำคัญของเทมเพลตได้อย่างแท้จริง โชคดีที่มีข้อมูลมากมายในด้านนี้ ดังนั้นฉันจะไม่ลงรายละเอียดที่นี่ กลับไปที่ตัวควบคุมการแบ่งหน้า โดยมีปุ่มสี่ปุ่ม: หน้าแรก หน้าก่อนหน้า หน้าถัดไป หน้าสุดท้าย และแน่นอนว่าเป็นหมายเลขของแต่ละหน้า ปุ่มนำทางทั้งสี่ปุ่มถูกเลือกจากคลาส ImageButton แทนที่จะเป็นคลาส LinkButton จากมุมมองของการออกแบบเว็บแบบมืออาชีพ ปุ่มกราฟิกจะมีประโยชน์มากกว่าลิงก์ที่ซ้ำซากจำเจอย่างเห็นได้ชัด
ImageButton สาธารณะ FirstButton {รับ {return First;}}
ImageButton สาธารณะ LastButton {รับ {return Last;}}
ImageButton สาธารณะ PreviousButton {รับ {return ก่อนหน้า;}}
public ImageButton NextButton{get {return Next;}}
หมายเลขเพจถูกสร้างขึ้นแบบไดนามิก เนื่องจากขึ้นอยู่กับจำนวนเรคคอร์ดในแหล่งข้อมูลและจำนวนเรคคอร์ดที่แสดงในแต่ละเพจ หมายเลขหน้าจะถูกเพิ่มลงในแผง และนักออกแบบเว็บไซต์สามารถใช้แผงเพื่อระบุตำแหน่งที่จะแสดงหมายเลขหน้า กระบวนการสร้างหมายเลขหน้าจะมีการกล่าวถึงโดยละเอียดในภายหลัง ตอนนี้เราจำเป็นต้องจัดเตรียมเทมเพลตสำหรับการควบคุมเพจ เพื่อให้ผู้ใช้สามารถกำหนดลักษณะที่ปรากฏของตัวควบคุมเพจได้
[คอนเทนเนอร์เทมเพลต(typeof(LayoutContainer))]
เค้าโครง ITemplate สาธารณะ
-
รับ {กลับมา (_layout;}
ตั้งค่า {_layout = ค่า;}
}
คลาสสาธารณะ LayoutContainer:Control,INamingContainer
-
คอนเทนเนอร์เค้าโครงสาธารณะ()
{this.ID = "เพจ";}
-
คลาส LayoutContainer จัดเตรียมคอนเทนเนอร์สำหรับเทมเพลต โดยทั่วไป การเพิ่ม ID ที่กำหนดเองลงในคอนเทนเนอร์เทมเพลตถือเป็นเรื่องดีเสมอ ซึ่งจะหลีกเลี่ยงปัญหาในการจัดการเหตุการณ์และการเรียกเพจ แผนภาพ UML ต่อไปนี้อธิบายกลไกการนำเสนอของตัวควบคุมเพจ
รูปที่ 5
ขั้นตอนแรกในการสร้างเทมเพลตคือการกำหนดเค้าโครงในหน้า aspx:
<เค้าโครง>
<asp:ImageButton id = "แรก" Runat = "เซิร์ฟเวอร์" imageUrl = "play2L_dis.gif"
AlternateText="Home"></asp:ImageButton>
<asp:ImageButton id = "ก่อนหน้า" Runat = "เซิร์ฟเวอร์" imageUrl = "play2L.gif"
AlternateText="ก่อนหน้า"></asp:ImageButton>
<asp:ImageButton id = "ถัดไป" Runat = "เซิร์ฟเวอร์" imageUrl = "play2.gif"
AlternateText="หน้าถัดไป"></asp:ImageButton>
<asp:ImageButton id = "สุดท้าย" Runat = "เซิร์ฟเวอร์" imageUrl = "play2_dis.gif"
AlternateText="หน้าสุดท้าย"></asp:ImageButton>
<asp:Panel id="Pager" Runat="server""></asp:Panel">
</LAYOUT>
ตัวอย่างเค้าโครงนี้ไม่มีองค์ประกอบรูปแบบใดๆ เช่น ตาราง ฯลฯ แน่นอนว่าแอปพลิเคชันจริงสามารถ (และควร) เพิ่มองค์ประกอบรูปแบบได้ โปรดดูคำแนะนำเพิ่มเติมในภายหลัง
อินเทอร์เฟซ Itemplate จัดเตรียม InstantiateIn เพียงวิธีเดียวเท่านั้น ซึ่งจะแยกวิเคราะห์เทมเพลตและผูกคอนเทนเนอร์
โมฆะส่วนตัว InstantiateTemplate()
-
_container = เลย์เอาต์คอนเทนเนอร์ใหม่ ();
เค้าโครง.InstantiateIn(_container);
แรก = (ImageButton)_container.FindControl("ครั้งแรก");
ก่อนหน้า = (ImageButton)_container.FindControl("ก่อนหน้า");
ถัดไป = (ImageButton)_container.FindControl("ถัดไป");
สุดท้าย = (ImageButton)_container.FindControl("สุดท้าย");
Holder = (แผง)_container.FindControl("เพจเจอร์");
this.First.Click += System.Web.UI.ImageClickEventHandler ใหม่ (this.First_Click);
this.Last.Click += ใหม่ System.Web.UI.ImageClickEventHandler(this.Last_Click);
this.Next.Click += ใหม่ System.Web.UI.ImageClickEventHandler(this.Next_Click);
this.Previous.Click += ใหม่ System.Web.UI.ImageClickEventHandler(this.Previous_Click);
}
สิ่งแรกที่เมธอด InstatiateTemplate ของตัวควบคุมทำคือสร้างอินสแตนซ์ของเทมเพลต นั่นคือ เรียก Layout.InstantiateIn(_container) จริงๆ แล้วคอนเทนเนอร์คือตัวควบคุมชนิดหนึ่ง และการใช้งานก็คล้ายกับตัวควบคุมอื่นๆ เมธอด InstantiateTemplate ใช้ฟีเจอร์นี้เพื่อค้นหาปุ่มนำทางสี่ปุ่มและแผงที่ใช้เก็บหมายเลขหน้า ปุ่มนำทางจะพบได้จาก ID นี่เป็นข้อจำกัดเล็กๆ น้อยๆ ในการควบคุมเพจ: ปุ่มนำทางจะต้องมี ID ที่ระบุ ซึ่งได้แก่ First, Previous, Next และ Last นอกจากนี้ ID ของ Panel จะต้องเป็น Pager มิฉะนั้นจะไม่ใช่ พบ. น่าเสียดายที่นี่น่าจะเป็นแนวทางที่ดีกว่าสำหรับกลไกการนำเสนอที่เราเลือก แต่หวังว่าด้วยเอกสารประกอบที่เหมาะสม ข้อจำกัดเล็กๆ น้อยๆ นี้จะไม่ทำให้เกิดปัญหาใดๆ อีกทางเลือกหนึ่งคือให้แต่ละปุ่มสืบทอดจากคลาส ImageButton ดังนั้นการกำหนดประเภทใหม่ เนื่องจากแต่ละปุ่มเป็นประเภทที่แตกต่างกัน การค้นหาแบบเรียกซ้ำสามารถนำไปใช้ในคอนเทนเนอร์เพื่อค้นหาปุ่มเฉพาะต่างๆ โดยไม่จำเป็นต้องใช้ ID ของปุ่ม คุณลักษณะ.
หลังจากที่คุณพบปุ่มทั้งสี่แล้ว ให้ผูกตัวจัดการเหตุการณ์ที่เหมาะสมเข้ากับปุ่มเหล่านั้น ต้องทำการตัดสินใจที่สำคัญที่นี่ กล่าวคือ เมื่อใดจึงจะเรียก InstantiateTemplate โดยทั่วไป ควรเรียกวิธีการชนิดนี้ในวิธีการ CreateChildControls เนื่องจากวัตถุประสงค์หลักของวิธีการ CreateChildControls คืองานประเภทนี้ในการสร้างตัวควบคุมลูก เนื่องจากตัวควบคุมเพจไม่เคยแก้ไขตัวควบคุมลูก จึงไม่จำเป็นต้องใช้ฟังก์ชันที่ CreateChildControls จัดเตรียมไว้เพื่อปรับเปลี่ยนสถานะการแสดงผลตามเหตุการณ์บางอย่าง ยิ่งแสดงการควบคุมลูกได้เร็วเท่าไรก็ยิ่งดีเท่านั้น ดังนั้น ตำแหน่งที่เหมาะที่สุดในการเรียกเมธอด InstantiateTemplate ก็คือในเหตุการณ์ OnInit
การป้องกันการแทนที่เป็นโมฆะ OnInit (EventArgs e)
-
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += ตัวจัดการเหตุการณ์ใหม่ (BoundControl_DataBound);
อินสแตนซ์เทมเพลต();
ควบคุมเพิ่ม(_คอนเทนเนอร์);
ฐาน OnInit(e);
}
นอกเหนือจากการเรียกเมธอด InstantiateTemplate แล้ว เมธอด OnInit ยังมีงานที่สำคัญอีกประการหนึ่งในการเพิ่มคอนเทนเนอร์ให้กับตัวควบคุมเพจ หากคุณไม่เพิ่มคอนเทนเนอร์ลงในคอลเลกชันควบคุมของเพจเจอร์ เทมเพลตจะไม่แสดงเนื่องจากเมธอด Render จะไม่ถูกเรียกใช้
เทมเพลตยังสามารถกำหนดโดยทางโปรแกรมได้โดยใช้อินเทอร์เฟซ Itemplate นอกเหนือจากการเป็นการวัดเพื่อเพิ่มความยืดหยุ่นแล้ว คุณลักษณะนี้ยังสามารถจัดเตรียมเทมเพลตเริ่มต้นเพื่อใช้เมื่อผู้ใช้ไม่ได้จัดเตรียมเทมเพลตผ่านเพจ aspx
คลาสสาธารณะ DefaultPagerLayout:ITemplate
-
ImageButton ส่วนตัวถัดไป;
ImageButton ส่วนตัวก่อน;
ImageButton ส่วนตัวล่าสุด;
ImageButton ส่วนตัวก่อนหน้า;
เพจเจอร์แผงส่วนตัว
DefaultPagerLayout สาธารณะ ()
-
ถัดไป = ImageButton ใหม่ ();
อันดับแรก = ImageButton ใหม่ ();
สุดท้าย = ImageButton ใหม่ ();
ก่อนหน้า = ImageButton ใหม่ ();
เพจเจอร์ = แผงใหม่ ();
Next.ID = "Next"; Next.AlternateText = "หน้าถัดไป"; Next.ImageUrl = "play2.gif";
First.ID="First"; First.AlternateText="Home";First.ImageUrl="play2L_dis.gif";
Last.ID = "Last"; Last.AlternateText = "หน้าสุดท้าย"; Last.ImageUrl="play2_dis.gif";
Previous.ID="ก่อนหน้า"; Previous.AlternateText="หน้าก่อนหน้า";Previous.ImageUrl="play2L.gif";
Pager.ID="เพจเจอร์";
-
โมฆะสาธารณะ InstantiateIn (การควบคุมการควบคุม)
-
ควบคุมการควบคุมล้าง();
ตาราง ตาราง = ตารางใหม่ ();
table.BorderWidth = หน่วย.พิกเซล(0);
ตาราง CellSpacing= 1;
ตาราง CellPadding =0;
แถว TableRow = TableRow ใหม่ ();
row.VerticalAlign = VerticalAlign.Top;
ตาราง.Rows.Add(แถว);
เซลล์ TableCell = TableCell ใหม่ ();
cell.HorizontalAlign = VerticalAlign.Right;
cell.VerticalAlign = VerticalAlign.Middle;
เซลล์Controls.Add(ครั้งแรก);
cell.Controls.Add (ก่อนหน้า);
แถวเซลล์เพิ่ม(เซลล์);
เซลล์ = TableCell ใหม่ ();
cell.HorizontalAlign=HorizontalAlign.Center;
เซลล์Controls.Add(เพจเจอร์);
แถวเซลล์เพิ่ม(เซลล์);
เซลล์ = TableCell ใหม่ ();
cell.VerticalAlign = VerticalAlign.Middle;
เซลล์Controls.Add(ถัดไป);
cell.Controls.Add (สุดท้าย);
row.Cells.Add(เซลล์);
control.Controls.Add(ตาราง);
-
}
DefaultPagerLayout จัดเตรียมองค์ประกอบการนำทางทั้งหมดโดยทางโปรแกรมและเพิ่มลงในหน้า aspx แต่คราวนี้องค์ประกอบการนำทางจะถูกจัดรูปแบบด้วยตาราง HTML มาตรฐาน ในตอนนี้ หากผู้ใช้ไม่ได้จัดเตรียมเทมเพลตการนำเสนอ โปรแกรมก็จะจัดเตรียมเทมเพลตเริ่มต้นให้โดยอัตโนมัติ
[TemplateContainer(typeof(LayoutContainer))]
เค้าโครง ITemplate สาธารณะ
-
รับ {return (_layout == null)? DefaultPagerLayout():_layout;} ใหม่
ตั้งค่า {_layout = ค่า;}
}
มาดูกระบวนการสร้างเลขหน้าแต่ละหน้ากันดีกว่า การควบคุมเพจจำเป็นต้องกำหนดค่าคุณสมบัติบางอย่างก่อน และใช้ค่าคุณสมบัติเหล่านี้เพื่อกำหนดจำนวนหน้าที่แตกต่างกันที่จะสร้าง
สาธารณะ int CurrentPage
-
รับ
-
สตริง cur = (สตริง) ViewState ["หน้าปัจจุบัน"];
กลับ (cur == string.Empty || cur ==null)? 1 : int.Parse(cur);
-
ชุด
-
ViewState["CurrentPage"] = value.ToString();}
}
สาธารณะ int PagersToShow
-
รับ{ผลตอบแทน _ผลลัพธ์;}
ชุด {_results = ค่า;}
}
สาธารณะ int ResultsToShow
-
รับ {return _resultsperpage;}
ชุด {_resultsperpage = ค่า;}
}
CurrentPage จะบันทึกหน้าปัจจุบันใน ViewState ของหมายเลขหน้า คุณสมบัติที่กำหนดโดยวิธี PagersToShow ช่วยให้ผู้ใช้สามารถระบุจำนวนหน้าที่จะแสดงได้ ในขณะที่คุณสมบัติที่กำหนดโดย ResultsToShow ช่วยให้ผู้ใช้สามารถระบุจำนวนระเบียนที่จะแสดง แต่ละหน้า ค่าเริ่มต้นคือ 10
NumberofPagersToGenerate ส่งคืนจำนวนหน้าปัจจุบันที่ควรสร้างขึ้น
int PagerSequence ส่วนตัว
-
รับ
-
กลับ Convert.ToInt32
(Math.Ceiling((double)CurrentPage/(double)PagersToShow));}
} }
NumberOfPagersToGenerate int ส่วนตัว
-
รับ {ส่งคืน PagerSequence * PagersToShow;}
}
ส่วนตัว int TotalPagesToShow
-
รับ {return Convert.ToInt32(Math.Ceiling((double)TotalResults/(double)_resultsperpage));}
-
สาธารณะ int TotalResults
-
รับ {return _builder.Adapter.TotalCount;}
}
วิธีการ TotalPagesToShow ส่งคืนจำนวนหน้าทั้งหมดที่จะแสดง ปรับโดยคุณสมบัติ ResultsToShow ที่ตั้งไว้ล่วงหน้าของผู้ใช้
แม้ว่า ASP.NET จะกำหนดลักษณะเริ่มต้นบางอย่าง แต่อาจไม่เป็นประโยชน์สำหรับผู้ใช้การควบคุมเพจ ผู้ใช้สามารถปรับลักษณะที่ปรากฏของตัวควบคุมเพจผ่านสไตล์แบบกำหนดเองได้
สไตล์สาธารณะ UnSelectedPagerStyle {รับ {return UnselectedPager;}}
public Style SelectedPagerStyle {get {return SelectedPager;}}
UnSelectedPagerStyle จัดเตรียมสไตล์ที่ใช้เมื่อไม่ได้เลือกหมายเลขหน้า และ SelectedPagerStyle จัดเตรียมสไตล์ที่ใช้เมื่อเลือกหมายเลขหน้า
โมฆะส่วนตัว GeneratePagers (การควบคุม WebControl)
-
ควบคุมการควบคุมล้าง();
int pager = (PagerSequence-1)* PagersToShow +1;
for (;เพจเจอร์<=NumberOfPagersToGenerate && เพจเจอร์<=TotalPagesToShow;เพจเจอร์++)
-
ลิงค์ LinkButton = LinkButton ใหม่ ();
link.Text = เพจเจอร์ ToString();
link.ID = เพจเจอร์ ToString();
link.Click += ใหม่ EventHandler(this.Pager_Click);
ถ้า (link.ID.Equals(CurrentPage.ToString()))
link.MergeStyle(SelectedPagerStyle);
อื่น
link.MergeStyle(UnSelectedPagerStyle);
control.Controls.Add(ลิงก์);
control.Controls.Add(new LiteralControl(" "));
-
} }
โมฆะส่วนตัว GeneratePagers()
-
GeneratePagers (ผู้ถือ);
-
เมธอด GeneratePagers จะสร้างหมายเลขหน้าทั้งหมดแบบไดนามิก ซึ่งเป็นปุ่มประเภท LinkButton คุณลักษณะป้ายกำกับและ ID ของแต่ละหมายเลขหน้าถูกกำหนดผ่านการวนซ้ำ และในเวลาเดียวกัน เหตุการณ์การคลิกจะถูกผูกไว้กับตัวจัดการเหตุการณ์ที่เหมาะสม สุดท้าย หมายเลขหน้าจะถูกเพิ่มลงในตัวควบคุมคอนเทนเนอร์ - ในกรณีนี้คือวัตถุแผง รหัสปุ่มทำหน้าที่ระบุว่าปุ่มใดทำให้เกิดเหตุการณ์การคลิก ต่อไปนี้เป็นคำจำกัดความของตัวจัดการเหตุการณ์:
โมฆะส่วนตัว Pager_Click (ผู้ส่งวัตถุ System.EventArgs e)
-
ปุ่ม LinkButton = ผู้ส่ง (LinkButton);
CurrentPage = int.Parse(button.ID);
RaiseEvent(PageChanged, นี้, PageChangedEventArgs ใหม่ (CurrentPage, PagedEventInviver.Pager));
อัปเดต();
}
ส่วนตัวเป็นโมฆะ Next_Click (ผู้ส่งวัตถุ System.Web.UI.ImageClickEventArgs e)
-
ถ้า (หน้าปัจจุบัน<TotalPagesToShow)
หน้าปัจจุบัน++;
RaiseEvent(PageChanged, นี้, PageChangedEventArgs ใหม่ (CurrentPage, PagedEventInviver.Next));
อัปเดต();
}
ส่วนตัวเป็นโมฆะ Previous_Click (ผู้ส่งวัตถุ System.Web.UI.ImageClickEventArgs e)
-
ถ้า (หน้าปัจจุบัน > 1)
หน้าปัจจุบัน--;
RaiseEvent(PageChanged, นี้, PageChangedEventArgs ใหม่ (CurrentPage, PagedEventInviver.Previous));
อัปเดต();
-
โมฆะส่วนตัว First_Click (ผู้ส่งวัตถุ System.Web.UI.ImageClickEventArgs e)
-
หน้าปัจจุบัน = 1;
RaiseEvent(PageChanged, นี้, PageChangedEventArgs ใหม่ (CurrentPage, PagedEventInviver.First));
อัปเดต();
}
ส่วนตัวเป็นโมฆะ Last_Click (ผู้ส่งวัตถุ System.Web.UI.ImageClickEventArgs e)
-
หน้าปัจจุบัน = TotalPagesToShow;
RaiseEvent(PageChanged, นี้, PageChangedEventArgs ใหม่ (หน้าปัจจุบัน, PagedEventInviver.Last));
อัปเดต();
}
ตัวจัดการเหตุการณ์เหล่านี้คล้ายกันตรงที่เปลี่ยนเพจปัจจุบันของตัวควบคุมเพจก่อน จากนั้นจึงรีเฟรชตัวควบคุมที่ถูกผูกไว้
การอัปเดตโมฆะส่วนตัว ()
-
ถ้า (!HasParentControlCalledDataBinding) กลับมา;
ใช้กฎความไวข้อมูล ();
BindParent();
BoundControl.DataBind();
}
ขั้นแรก การควบคุมเพจจะตรวจสอบว่าอะแด็ปเตอร์ที่จำเป็นได้รับการเตรียมใช้งานหรือไม่ โดยการเรียกเมธอด HasParentControlCalledDataBinding ถ้าเป็นเช่นนั้น ให้ใช้กฎที่ระบุไว้ก่อนหน้านี้สำหรับการปรับการควบคุมตามเงื่อนไขการแสดงข้อมูลกับการควบคุมปัจจุบันโดยอัตโนมัติ แม้ว่ากฎเหล่านี้จะถูกควบคุมภายในโดยการควบคุมเพจ แต่กฎเหล่านี้สามารถย้ายออกจากการควบคุมได้อย่างง่ายดายโดยใช้โหมดสถานะ [GoF] เมื่อจำเป็น
บูลสาธารณะ IsDataSensitive
-
รับ {return _isdatasensitive;}
ชุด {_isdatasensitive = ค่า;}
}
บูลส่วนตัว IsPagerVisible
-
รับ {return (TotalPagesToShow != 1) && IsDataSensitive;}
}
บูลส่วนตัว IsPreviousVisible
-
รับ
-
กลับ (!IsDataSensitive) จริงหรือไม่:
(หน้าปัจจุบัน != 1);
-
}
บูลส่วนตัว IsNextVisible
-
รับ
-
กลับ (!IsDataSensitive) จริงหรือไม่:
(หน้าปัจจุบัน != TotalPagesToShow);
-
}
โมฆะส่วนตัว ApplyDataSensitivityRules()
-
FirstButton.Visible = IsPreviousVisible;
PreviousButton.Visible = IsPreviousVisible;
LastButton.Visible = IsNextVisible;
NextButton.Visible = IsNextVisible;
ถ้า (IsPagerVisible) GeneratePagers();
}
วิธีการ ApplyDataSensitivityRules ใช้กฎที่กำหนดไว้ล่วงหน้า เช่น IsPagerVisible, IsPreviousVisible และ IsNextVisible ตามค่าเริ่มต้น การควบคุมเพจจะเปิดใช้งานกฎเหล่านี้ แต่ผู้ใช้สามารถปิดได้โดยการตั้งค่าคุณสมบัติ IsDataSensitive
จนถึงขณะนี้ ส่วนการแสดงผลของตัวควบคุมเพจได้รับการออกแบบโดยทั่วไปแล้ว งานสุดท้ายที่เหลือคือการจัดหาตัวจัดการเหตุการณ์หลายตัว เพื่อให้ผู้ใช้สามารถทำการปรับเปลี่ยนที่จำเป็นเมื่อมีเหตุการณ์การควบคุมเพจต่างๆ เกิดขึ้น
ผู้รับมอบสิทธิ์สาธารณะถือเป็นโมฆะ PageDelegate (ผู้ส่งวัตถุ PageChangedEventArgs e);
enum สาธารณะ PagedEventInviver {ถัดไป, ก่อนหน้า, ครั้งแรก, สุดท้าย, Pager}
คลาสสาธารณะ PageChangedEventArgs:EventArgs
-
หน้าใหม่ int ส่วนตัว;
ผู้เรียกใช้ Enum ส่วนตัว
PageChangedEventArgs สาธารณะ (int newpage): ฐาน ()
-
this.newpage = หน้าใหม่;
-
PageChangedEventArgs สาธารณะ (int newpage, ผู้เรียกใช้ PagedEventInviver)
-
this.newpage = หน้าใหม่;
this.inviver = ผู้เรียกใช้;
-
สาธารณะ int NewPage {get{return newpage;}}
สาธารณะ Enum EventInviver {รับ {return inviver;}}
-
เนื่องจากการควบคุมเพจจำเป็นต้องส่งคืนพารามิเตอร์เหตุการณ์ที่กำหนดเอง เราจึงกำหนดคลาส PageChangedEventArgs เฉพาะ คลาส PageChangedEventArgs ส่งคืนชนิด PagedEventInviver ซึ่งเป็นตัวแจงนับของตัวควบคุมที่อาจทริกเกอร์เหตุการณ์ เพื่อที่จะจัดการพารามิเตอร์เหตุการณ์ที่กำหนดเอง เราจะกำหนดผู้รับมอบสิทธิ์ใหม่ ซึ่งก็คือ PageDelegate เหตุการณ์ถูกกำหนดในรูปแบบต่อไปนี้:
กิจกรรมสาธารณะ PageDelegate PageChanged;
เหตุการณ์สาธารณะ EventHandler DataUpdate
เมื่อเหตุการณ์ไม่มีตัวฟังเหตุการณ์ที่สอดคล้องกัน ASP.NET จะส่งข้อยกเว้น การควบคุมเพจกำหนดวิธีการ RaiseEvent ต่อไปนี้
โมฆะส่วนตัว RaiseEvent (EventHandler e, ผู้ส่งวัตถุ)
-
this.RaiseEvent (อี, นี่, null);
}
โมฆะส่วนตัว RaiseEvent (EventHandler e, ผู้ส่งวัตถุ, PageChangedEventArgs args)
-
ถ้า(e!=null)
-
e(ผู้ส่ง,args);
-
-
โมฆะส่วนตัว RaiseEvent (PageDelegate e, ผู้ส่งวัตถุ)
-
this.RaiseEvent (อี, นี้, null);
}
โมฆะส่วนตัว RaiseEvent (PageDelegate e, ผู้ส่งวัตถุ, PageChangedEventArgs args)
-
ถ้า(e!=null)
-
e(ผู้ส่ง,args);
-
}
ตัวจัดการเหตุการณ์สามารถเรียกเหตุการณ์โดยเรียกวิธีการเพิ่มรายบุคคล
4. ตัวอย่างแอปพลิเคชัน
ณ จุดนี้การออกแบบการควบคุมการเพจเสร็จสมบูรณ์และสามารถใช้อย่างเป็นทางการได้ ในการใช้การควบคุมการเพจเพียงแค่ผูกมันเข้ากับการควบคุมการนำเสนอ
<asp: repeater id = "repeater" runat = "เซิร์ฟเวอร์">
<เทมเพลตรายการ>
คอลัมน์ 1:
<%# convert.toString (databinder.eval (container.dataitem, "column1"))%>
<br>
คอลัมน์ 2:
<%# convert.toString (databinder.eval (container.dataitem, "column2"))%>
<br>
คอลัมน์ 3:
<%# convert.toString (databinder.eval (container.dataitem, "column3"))%>
<br>
<ชม.>
</เทมเพลตรายการ">
</asp: repeater>
<CC1: Pager ID = "Pager" ResultStoshow = "2" Runat = "Server" BindTocontrol = "Repeater">>
<selectedPagerstyle backcolor = "เหลือง" />
</CC1: เพจเจอร์>
หน้า ASPX ด้านบนเชื่อมโยงการควบคุมการเพจกับตัวควบคุม repeater ตั้งค่าจำนวนระเบียนที่แสดงในแต่ละหน้าเป็น 2 สีของหมายเลขหน้าที่เลือกเป็นสีเหลืองและใช้เค้าโครงเริ่มต้น ดังแสดงในรูปที่ 1 ด้านล่างเป็นอีกตัวอย่างหนึ่งซึ่งเชื่อมโยงการควบคุมการเพจกับ DataGrid ดังแสดงในรูปที่ 2
<asp: dataGrid id = "grid" runat = "เซิร์ฟเวอร์" ></asp: dataGrid>
<CC1: Pager ID = "pagerGrid" resultStoshow = "2" runat = "เซิร์ฟเวอร์" bindtocontrol = "grid">>>
<selectedPagerstyle backcolor = "red" ></selectedPagerStyle>
<เลย์เอาต์>
<ASP: ImageButton ID = "First" Runat = "Server" ImageUrl = "play2l_dis.gif" AlternateText = "Home" ></ASP: ImageButton>
<ASP: ImageButton ID = "ก่อนหน้า" "runat =" เซิร์ฟเวอร์ "imageUrl =" play2l.gif "allertetext =" หน้าก่อนหน้า "></asp: imageButton>
<ASP: ImageButton ID = "Next" Runat = "Server" ImageUrl = "play2.gif" AlternateText = "หน้าถัดไป" ></ASP: ImageButton>
<asp: imageButton id = "สุดท้าย" runat = "เซิร์ฟเวอร์" imageUrl = "play2_dis.gif" oulderetetext = "หน้าสุดท้าย" ></asp: imageButton>
<ASP: Panel ID = "Pager" Runat = "Server" ></ASP: Panel>
</เลย์เอาต์>
</CC1: Pager>
การทดสอบแสดงให้เห็นว่าการควบคุมการเพจไม่ได้ขึ้นอยู่กับการควบคุมการนำเสนอที่เฉพาะเจาะจง ตัวอย่างที่สมบูรณ์
แม้ว่าการเรียนรู้ที่จะพัฒนาตัวควบคุมเว็บที่กำหนดเองไม่ใช่เรื่องง่าย แต่ประโยชน์ของการเรียนรู้ทักษะนี้ชัดเจนด้วยตนเอง เวลา
http://www.cnblogs.com/niit007/archive/2006/08/13/475501.html