680 likes | 1.24k Views
2. Agenda. Part 1Tour of new core features in Whidbey for server control authoringSimpler compositionClient-script supportScript OMWeb ResourcesCallbacksControl stateAdaptationReal world sample: HtmlEditor control. Part 2Data Controls ArchitectureDataSource controlsData-bound controlsAutomatic data-binding and editingDesigner FrameworkData-aware designersInteractive designersReal world samples: BlogDataSource and BlogEntryView controls.
E N D
1. 1 Building Server Controls For ASP.NET “Whidbey” (Part 2) Nikhil Kothari (nikhilko@microsoft.com)
Development Lead, Web Platform and Tools Team
Microsoft Corporation
2. 2 Agenda Part 1
Tour of new core features in Whidbey for server control authoring
Simpler composition
Client-script support
Script OM
Web Resources
Callbacks
Control state
Adaptation
Real world sample: HtmlEditor control Part 2
Data Controls Architecture
DataSource controls
Data-bound controls
Automatic data-binding and editing
Designer Framework
Data-aware designers
Interactive designers
Real world samples: BlogDataSource and BlogEntryView controls
3. 3 ASP.NET Control Framework Rich framework to enable building “smart” server controls
Same model as v1, but enables much more
New control types and scenarios
Controls with declarative programming model
Improved design-time experience for controls
Extends v1 framework, while preserving existing knowledge and compatibility
What’s new?
Provide new services and framework features
Simplify development with more functional base classes targeting common scenarios
Incorporate learning and general recommended patterns
4. 4 Blogging Controls The finished result…
BlogEntryView
BlogDataSource
5. 5 BlogEntryView Design
6. 6 Blogging Controls Markup <pdc:BlogDataSource id=“blogDS1” runat=“server”
EntryPath=“BlogEntries”
AdminRoleGroups=“Admin” />
<pdc:BlogEntryView id=“be1” runat=“server”
DataSourceID=“blogDS1” >
<EntryTemplate>
<asp:Label ... Text=‘<%# Eval(“Title”) %>’ />
</EntryTemplate>
<AddEntryTemplate>
<asp:TextBox ... Text=‘<%# Bind(“Title”) %>’ />
</AddEntryTemplate>
<EntryStyle Font-Name=“Georgia” Font-Size=“10pt” />
<AddEntryStyle BackColor=“Silver” />
</pdc:BlogEntryView>
7. 7 BlogEntryView Functionality Offers UI to display blog entries
UI can be customized via templates and styles
Additionally offers UI to post new blog entries
If the data source supports inserting rows
Implemented as a data-bound control
Entries are rendered by enumerating data from a data source
Enables declarative page authoring model
Both viewing and posting entries
8. 8 BlogDataSource Functionality Provides data source consisting of blog entries
Data store is a set of XML files in a folder within the Web application
Provides a tabular view of data
Each entry is a row with four columns: Title, Content, Category and PostDate
Enables posting new entries
If the user has the rights to do so
Determined by user roles
9. 9 Data Architecture Overview Goals
Simplify creation of data-driven applications
Declarative page authoring model for mainline scenarios
Simplify authoring of data controls
Preserve flexibility of v1 model
Two types of data controls
DataSource controls provide data
Data-bound controls enumerate records and render them on the page
Talk to each other using a standard interface
10. 10 Blog Data Controls at Work
11. 11 Mixing and Matching Data Controls
12. 12 DataSource Controls Provide data and implement data access logic
Load data on-demand
Implement two API models
Domain-specific
Consumed by page developer
SelectCommand on SqlDataSource; DataFile on XmlDataSource
Generic abstraction of data
Consumed by data-bound control author
Essentially a collection of one or more named views of data, each represented by a DataSourceView
Raise change notifications when data is modified, or query parameters are modified
Non-visual controls (no rendering)
13. 13 DataSource Control Types Tabular
Implement IDataSource
Typically derive from DataSourceControl
Usable by controls like GridView, and BlogEntryView
Hierarchical
Implement IHierarchicalDataSource
Typically derive from HierarchicalDataSourceControl
Usable by controls like TreeView, and Menu
Can be tabular or hierarchical or both
Only covering tabular data source controls today
14. 14 IDataSource and DataSourceControl public interface IDataSource {
event EventHandler DataSourceChanged;
DataSourceView GetView(string viewName);
ICollection GetViewNames();
}
public abstract class DataSourceControl : Control, IDataSource, IListSource {
}
15. 15 DataSourceView Allows enumerating a set of data records
IEnumerable at a minimum; IList if possible
Equivalent of a “SELECT” (required)
Optionally support paging, sorting
Optionally allows modifying the set of records
Equivalent of “UPDATE”, “INSERT” and “DELETE”
DataSourceView describes its capabilities
Capabilities may be a function of property settings
Or they may be fixed based on the back-end data store
16. 16 DataSourceView public abstract class DataSourceView {
protected DataSourceView(IDataSource owner, string name);
public virtual bool CanDelete { get; }
public virtual bool CanInsert { get; }
public virtual bool CanUpdate { get; }
public virtual bool CanSort { get; }
...
public string Name { get; }
public event Event DataSourceViewChanged;
public virtual int Delete(IDictionary keys);
public virtual int Insert(IDictionary values);
public virtual int Update(IDictionary keys,
IDictionary values);
public abstract IEnumerable Select(
DataSourceSelectArguments arguments);
}
17. 17 Data-bound Controls Associated with a DataSourceControl
Consume one or more DataSourceViews offered by the data source
Create visual rendering of data records
Optionally provide UI to manipulate data (sorting, editing, …)
Allow customization of UI via templates and styles
Allow programmatic customization of UI via events
18. 18 Data-bound Control Types Simple data-bound controls
Enumerate data records to create child objects
Derive from DataBoundControl
Eg. DropDownList and ListItems
Composite data-bound controls
Enumerate data records to create child controls
Derive from CompositeDataBoundControl
Eg. GridView and table rows
Hierarchical data-bound controls
Enumerate and navigate hierarchy in data records to create child objects with hierarchy
Derive from HierarchicalDataBoundControl
Eg. TreeView create TreeNodes
19. 19 Data-bound Control Base Classes Base class that implements the necessary plumbing
DataSource, DataSourceID and DataMember properties
Locate the associated DataSourceControl and retrieve its DataSourceView to allow enumerating and manipulate data
Perform automatic data-binding at the right time in the page lifecycle
Listen to change notifications from the DataSourceControl
Manage state and recreation of control hierarchy upon post-back
20. 20 Your Data-bound Controls Derive from the appropriate base class
Implement their UI creation using data
Implement rendering and handle events raised by their UI
Take advantage of capabilities offered by DataSourceViews.
21. 21 Data Control Base Classes
22. 22 Automatic Data-binding Automatically data-bind in OnPreRender
If bound to a DataSourceControl && RequiresDataBinding is true
When is RequiresDataBinding set to true?
OnLoad (if Page.IsPostBack is false)
OnInit (if EnableViewState is false)
Property changes (eg. DataSourceID)
DataSource raises a change event
Possible because a DataSourceControl can be located wihtin the Page, and IDataSource, DataSourceView provide the ability to load data on-demand
23. 23 Parameter Objects Declaratively specify the value for a parameter in a query in a DataSourceControl
Eg. SelectParameters property on SqlDataSourceControl
Different sources of values: Control properties, request variables, etc.
DataSourceControls track changes in parameter values and raise change notifications
DataBoundControls use this notification to register the need to DataBind
Automatically re-bind when the query parameters change
DataBound controls can provide values for parameters as well
Allows pushing of changed values from the data-bound UI into the data source
24. 24 IBindableTemplate Template with binding semantics added
ExtractValues() used to extract name/value pairs
Data-binding expressions
Bind() is special and defines a read/write data-binding
Others expressions are read-only
<pdc:BlogEntryView ...>
<AddEntryTemplate>
<asp:TextBox ... Text=‘<%# Bind(“Title”) %>’ />
<asp:TextBox ... Text=‘<%# Bind(“Content”) %>’ />
</AddEntryTemplate>
</pdc:BlogEntryView>
Text of controls are extracted as “Title” and “Content” values.
25. 25 Using an IBindableTemplate Mark your template property as a bindable template
TemplateContainer metadata attribute
Use IBindableTemplate::ExtractValues when you need to pull updated values from UI
Parser generates implementation of ExtractValues
Allows data-bound control to automatically retrieve updated values without requiring page developer to add logic
26. 26 Blogging Controls Code Walkthrough
BlogEntryView
BlogDataSource
27. 27 BlogEntryView Code public class BlogEntryView : CompositeDataBoundControl {
protected override int CreateChildControls(DataSourceView view,
bool dataBinding) {
// Enumerate data and create child controls
// BlogEntryView creates a table and instances of
// BlogEntryViewItems for each data record
}
protected bool RaiseBubbleEvent(object sender, EventArgs e) {
// Handle events bubbled by child controls
// BlogEntryView handles the “Add” Command event to add
// a new entry
}
protected override void Render(HtmlTextWriter writer) {
// Apply styles, etc. and then render child controls
}
}
28. 28 BlogEntryView Code protected override int CreateChildControls(DataSourceView view,
bool dataBinding) {
bool showAddEntry = view.CanInsert;
if (showAddEntry && (_addEntryTemplate != null)) {
BlogEntryViewItem entryContainer =
new BlogEntryViewItem(new BlogEntry());
Controls.Add(entryContainer);
_addEntryTemplate.InstantiateIn(entryContainer);
if (dataBinding) { entryContainer.DataBind(); }
}
int itemCount = 0;
IEnumerable dataSource = view.Select();
foreach (object o in dataSource) {
BlogEntryViewItem entryContainer = new BlogEntryViewItem(o);
Controls.Add(entryContainer);
_entryTemplate.InstantiateIn(entryContainer);
if (dataBinding) { entryContainer.DataBind(); }
itemCount++;
}
return itemCount;
}
29. 29 BlogEntryView Code private ITemplate _entryTemplate;
private ITemplate _addEntryTemplate;
[TemplateContainer(typeof(BlogEntryViewItem))]
public ITemplate EntryTemplate {
get { return _entryTemplate; }
set { _entryTemplate = value; }
}
[TemplateContainer(typeof(BlogEntryViewItem),
BindingDirection.TwoWay)]
public ITemplate AddEntryTemplate {
get { return _addEntryTemplate; }
set { _addEntryTemplate = value; }
}
30. 30 BlogEntryView Code private void OnAddEntry(BlogEntryViewItem item) {
IBindableTemplate bindableTemplate =
_addEntryTemplate as IBindableTemplate;
if (bindableTemplate != null) {
DataSourceView view = GetData();
IDictionary values = bindableTemplate.ExtractValues(item);
view.Insert(values);
}
}
protected override bool OnBubbleEvent(object source, EventArgs e) {
BlogEntryViewCommandEventArgs ce = e as BlogEntryViewCommandEventArgs;
if (ce != null) {
OnItemCommand(ce);
if (ce.CommandName == "Add") {
OnAddEntry(ce.Item);
}
return true;
}
return false;
}
31. 31 BlogDataSource Code public class BlogDataSource : DataSource {
public BlogDataSource() {
_entriesView = new BlogDataSourceView(this);
}
public string EntriesPath { get; set; }
protected override DataSourceView GetView(
string viewName) {
return _entriesView;
}
protected override ICollection GetViewNames() {
return new string[] { _entriesView.Name };
}
}
32. 32 BlogDataSourceView Code internal class BlogDataSourceView : DataSourceView {
private void EnsureEntries() {
BlogEntryCollection entries = new BlogEntryCollection();
foreach (string fileName in Directory.GetFiles(_path)) {
string fullPath = Path.Combine(_path, fileName);
using (FileStream fileStream = new FileStream(fullPath,
FileMode.Open, FileAccess.Read, FileShare.Read)) {
XmlSerializer serializer =
new XmlSerializer(typeof(BlogEntry));
entries.Add((BlogEntry)serializer.Deserialize(fileStream));
}
}
entries.Sort();
_entries = entries;
}
public override IEnumerable Select(DataSourceSelectArguments arguments) {
arguments.RaiseUnsupportedCapabilitiesError(this);
if (_entries == null) { EnsureEntries(); }
return new ArrayList(_entries);
}
}
33. 33 BlogDataSourceView Code public override bool CanInsert {
get { return (_path != null) && _owner.CanModify; }
}
public override int Insert(System.Collections.IDictionary values) {
string title = (string)values["Title"];
string content = (string)values["Content"];
string category = (string)values["Category"];
BlogEntry newEntry = new BlogEntry(title, content, category);
if (AutoSave) {
SaveEntry(newEntry);
}
if (_entries != null) {
_entries.Add(newEntry);
_entries.Sort();
}
OnDataSourceViewChanged(EventArgs.Empty);
return 1;
}
34. 34 Designer Framework Overview Builds on top of the v1 designer framework
Preserves the notion of Design-time HTML
Designer class is associated to the control class via the “Designer” metadata attribute
What’s new?
New, more functional base classes
DataBoundControlDesigner, CompositeControlDesigner, …
Simplified template editing
Interactive designers
Regions, Events, Tasks, and Painting
Slew of new services
Ability to navigate project/workspace tree, database schema, toolbox items etc.
Design-time state storage
35. 35 Blogging Controls Design-time The finished design experience…
BlogEntryView
BlogDataSourceControl
36. 36 Blogging Controls Design-time
37. 37 Blogging Controls Design-time
38. 38 BlogEntryView Design-time Functionality Provides the ability to bind the control to any tabular data source
Guides the user by providing tasks
Provides a realistic rendering of control on design surface
Distinguishes between sample and live data
Interacts with design of associated DataSourceControl to consume its schema, and sample data
Enables editing of template properties
Multiple views: Preview and Edit views
Edit views allows in-place editing of templates
39. 39 BlogDataSource Design-time Functionality Renders as a non-visual control
Allows selecting folder containing blog entries
Offers schema describing the data it offers
Generates sample data used by data-bound controls to DataBind at design-time
Allows page developer to choose between sample and live data
40. 40 Data Control Designers Data source controls designers
Derive from DataSourceControlDesigner
Offer schema at design-time to drive designer UI
Data-bindings dialog
Offer design-time data for use in designer
Data-bound control designers
Derive from DataBoundControlDesigner
Hook up with DataSourceControl and its designer
Use design-time data to create rendering on design surface
All of this is actually implemented by the base class!
41. 41 Blogging Controls Design-time Data Control Designers Code Walkthrough
42. 42 BlogDataSourceDesigner Code public class BlogDataSourceControlDesigner : DataSourceControlDesigner {
public override IDataSourceSchema Schema {
get {
return new TypeSchema(typeof(BlogEntry));
}
}
public override IEnumerable GetDesignTimeData(
string viewName, int minimumRows) {
// Generate sample data based on the schema
// and semantics of the data source
}
}
43. 43 BlogEntryViewDesigner Code public class BlogEntryViewDesigner :
DataBoundControlDesigner, IDynamicControlDesigner {
public override DesignerActionListCollection Actions { get; }
public override TemplateGroupCollection TemplateGroups { get; }
public override string GetDesignTimeHtml(
DesignerRegionCollection regions);
public override string GetEditableDesignerRegionContent(
EditableDesignerRegion region);
public override void SetEditableDesignerRegionContent(
EditableDesignerRegion region, string content);
public override void OnClick(DesignerRegionEventArgs e);
public overide void OnPaint(PaintEventArgs e);
}
44. 44 Tasks Ability to highlight core actions, properties and scenarios
Properties show up as textboxes or dropdowns
Properties can be design-time only properties
Hyperlinks serve as quick actions, or wizard launch points
Task panel is associated with a control on the design surface
Recommend keeping it small and focused
Not a replacement for the property grid
45. 45 Tasks Implement a class deriving from DesignerActionList
Properties on the class surface on the task panel to create editing UI
Methods on the class surface on the task panel as hyperlinks
Hand out an instance of this class by overriding the Actions property on your control designer
46. 46 Blogging Controls Design-time Tasks Code Walkthrough
47. 47 Tasks Code internal class BlogEntryViewDesignerActionList :
DesignerActionList {
public BlogEntryViewMode Mode { get; set; }
public override DesignerActionItem[] GetItems() {
return new DesignerActionItem[] {
new DesignerActionItem(“Mode”, “Current Mode:”);
}
}
}
// In BlogEntryViewDesigner
public override DesignerActionListCollection Actions {
get {
DesignerActionListCollection actions =
base.Actions;
DesignerActionList myActions =
new BlogEntryViewDesignerActionList(this);
actions.Add(myActions);
return actions;
}
}
48. 48 Regions Design-time HTML can be adorned with “regions”
Regions are rectangles of interactivity within the bounds of the control on the design surface
Selection within the control
Editing within the control
Generate events such as “Click”
Allow you to implement a custom version of content editing
When the banded templated editing model is not appropriate for your control
Useful if your control is read-only with interspersed editing areas
49. 49 Regions BlogEntryViewDesigner design-time HTML
<table>
<tr>
<td _designerRegion=“0”>Normal View</td>
<td _designerRegion=“1”>Admin View</td>
</tr>
<tr>
<td colspan=“2” _designerRegion=“3”>...</td>
</tr>
</table>
50. 50 Designer Events Control designers can handle user actions such as Clicks on the control
Override OnClick method on ControlDesigner
If the click is within the bounds of a region, that is handed in via the EventArgs
51. 51 Blogging Controls Design-time Regions and Events Code Walkthrough
52. 52 Regions Code protected override string GetDesignTimeHtml(DesignerRegionCollection regions) {
DesignerRegion normalModeRegion =
new DesignerRegion(this, “Normal”);
DesignerRegion adminModeRegion =
new DesignerRegion(this, “Admin”);
regions.Add(normalModeRegion);
regions.Add(adminModeRegion);
string designTimeHtml;
// Build design-time HTML containing tags
// with the “__designerRegion” attribute whose
// value is set to the index of the region in the
// regions collection
return designTimeHtml;
}
53. 53 Designer Events Code protected override void OnClick(RegionEventArgs e) {
if (e.Region == null) {
return;
}
if (e.Region.Name == “Normal”) {
// switch to normal mode;
}
else if (e.Region.Name == “Admin”) {
// switch to admin mode
}
UpdateView();
}
54. 54 Painting on Design Surface Control designers can paint on the design surface
Controls are handed a PaintEventArgs object which contains the bounds of the rectangle, and the Graphics object
Use GDI+ to draw on top of the rendered design-time HTML
Register to participate in the rendering process by choosing to custom paint in your control designer’s Initialize method
55. 55 Blogging Controls Design-time Painting Code Walkthrough
56. 56 Design-time Painting Code protected override void OnPaint(PaintEventArgs e) {
bool sampleData = false;
// logic to compute sampleData
if (sampleData) {
Graphics g = e.Graphics;
// Logic to compute widths, heights etc.
using (Font font = new Font("Tahoma", 60, FontStyle.Bold)) {
SizeF textSize = g.MeasureString(“Sample”, font);
g.DrawString(“Sample”, font, Brushes.Silver,
-textSize.Width / 2, -textSize.Height / 2);
}
}
}
public override void Initialize(IComponent component) {
// Initialization logic
// Turn on custom painting
SetViewFlags(ViewFlags.CustomPaint, true);
}
57. 57 Key Takeaways Think big!
Server controls define the Web development experience
“Whidbey” server controls are more powerful and functional
Enable core scenarios in a declarative manner
Framework enables authoring rich server controls
New scenarios and opportunities
Consistent data-bound and data source controls
Compelling design-time experience
Build on top of v1 server control and designer architecture
58. 58 Related Talks WSV401 – Building Server Controls for ASP.NET “Whidbey” (Part 1)
WSV200 – ASP.NET: Overview of ASP.NET “Whidbey”
WSV310 and WSV311 – ASP.NET: Programming with the Data Controls in ASP.NET “Whidbey” (Part 1 and 2)
59. 59 Download Slides/Demos Blog
http://www.nikhilk.net
(With ongoing updates to samples)
ASP.NET Web site
http://www.asp.net/whidbey
60. 60 Questions and answers…
61. 61 Abstract Learn about advanced topics in the server control architecture in ASP.NET “Whidbey” and how you can use them to build data-bound and data source components. In addition, learn how to use the new designer framework capabilities to enable a rich, interactive, RAD design-time experience for your controls. This talk will feature the BlogEntryView and BlogDataSource server controls that demonstrate writing Data controls, automatic data-binding and data editing, design time schema, tasks and in-place editing.
62. 62
63. 63 Bonus Material Simplified Template Editing
Using infrastructure services
64. 64 Template Editing Control designer simply defines its templates, their names and their visual style characteristics
The v1 semantics of Template groups containing one or more templates goes forward
Control designer offers a collection of TemplateGroups
Each TemplateGroup contains one or more TemplateDefinitions
The design surface does the rest!
65. 65 Blogging Controls Design-time Template Editing Code Walkthrough
66. 66 Template Editing Code private TemplateGroup _singleEntryTemplateGroup;
public override TemplateGroupCollection TemplateGroups {
get {
TemplateGroupCollection groups =
base.TemplateGroups;
if (_singleEntryTemplateGroup == null) {
// Show creating a template group
}
groups.Add(_singleEntryTemplateGroup);
return groups;
}
}
67. 67 Infrastructure Services ASP.NET provides several infrastructure services
Membership and Roles
SiteCounters
Profile and Personalization
Image generation
…
Infrastructure services are implemented as providers implementing a standard interface
Custom provider implementation can be swapped in
Controls can talk to the registered provider
Eg. Login control talks to the Membership provider
Same Control UI and object model automatically work against any provider selected by the app developer
68. 68 Using the Roles Service Add AddEntryRoles property on BlogDataSource
public string[] AdminRoleGroups { get; set; }
At runtime, check if the user is in the list of specified roles to automatically enable Inserting capability in the DataSourceView
bool canModify = false;
if (Page.Request.IsAuthenticated) {
foreach (string role in roles.Split(‘,’)) {
if (Roles.IsUserInRole(userName, role)) {
canModify = true;
break;
}
}
}