Rad Controls Ajax Course Ware
Rad Controls Ajax Course Ware
Rad Controls Ajax Course Ware
NET AJAX
RadControls for ASP.NET AJAX
861-862 862-871 871-876 876-879 879-881 881-888 888-899 899-903 903 903-907 907-910 910-916 916-922 922-925 925-926 927 927 927-930 930-931 931-935 935 935
Introduction
You have never used AJAX or any of the Microsoft AJAX controls and want to learn what its all about. You have used AJAX or some kind of AJAX based controls and want to learn the Telerik approach using RadControls for ASP.NET AJAX. You have used previous versions of RadControls and want to learn how to use RadControls for ASP.NET AJAX. You have used RadControls for ASP.NET AJAX and want to make your knowledge more comprehensive. ddd
1.2 What Do You Need To Have Before You Read This Courseware?
Computer Setup
Windows XP Professional or Windows Vista Service Pack 1. Microsoft .NET Framework 3.5. Internet Information Services 6. Internet Explorer 7 Microsoft Visual Studio 2008 Microsoft SQL Server Express or Microsoft SQL Server 2005 or above. RadControls for ASP.NET AJAX. You can purchase RadControls for ASP.NET AJAX from: http://www.telerik.com/purchase/purchase-online.aspx or download the trial from: http://www.telerik.com/products/aspnet-ajax/download.aspx
Learn more about system requirements for RadControls forASP.NET AJAXhere (http://www.telerik.com/products/aspnet-ajax/system-requirements.aspx).
The courseware has chapters on groups of RadControls where there are similarities between the controls. For example, all of the navigation controls are more alike than similar when it comes to the API and the design-time environment. This allows you to leverage a common set of skills between controls.
There are separate chapters for controls that don't fit together in a category with other controls, or are larger and more involved, such as the grid, editor or chart controls. We have also added steps on how to create a demonstration application "ActiveSkill". These chapters leverage your knowledge from preceding sections to see how the controls are used together in a closer-toreal-world setting. ActiveSkill is quite a bit smaller than a production application, but also larger than your typical demo application that may only use one or two controls at a time.
A list of the objectives to be accomplished in the chapter. Abrief introduction to orientate you to the "why and where" each control should be used. A"Getting Started" tutorial to get your feet wet with the control. A tour of the design-time interface and a brief overview of significant control properties or groups of properties. A guide to the server-side capabilities of the control with the focus on important properties, collections and methods. A review of the client-side API that demonstrates how to get references to the control's client object, methods and events. A brief review of the objectives that were accomplished.
The "ActiveSkill" chapters will only have the objectives and summary. The body of these chapters will be the steps to build the ActiveSkill application.
Chapter Summary
Navigation Controls
This chaptertours "navigation" related RadControls so you can became familiar with how and where each of these controls are used. You will see some of the important properties, methods and events that arecommon between navigation controls. You will create a simple application that used the menu, tab strip and tool bar controls. This chapter shows common server-side tasks such as add/edit/delete, iterating items in a collection and locating items based on various criteria (i.e. text, value or attribute). This chapter also shows some control-specific tasks such as working with the tab strip and Multi-Page together and using the context menu.
Input Controls
This chapter tours "input" related RadControls. The chapter shows significant properties and notes common properties shared by input controls. You will build a simple application that used all four types of input control and makes use of common properties such as labels and empty messages. You will learn how to use the serverside API to respond to user input and to create input controls dynamically. The chapter demonstrates how to perform common client-side tasks such as enabling and disabling some controls based on the responses to others, restricting input as the user types, and handling parsing errors. The chapter also shows how to use input controls with other controls such as an ASP.NET validator or RadSpellCheck.
Client-Side API
This chapter demonstrates basic techniques used to obtain RadControl object references in client code, how to call client methods and use properties of the client objects. You will learn the consistent naming convention used throughout the RadControls client API so that you can re-apply that knowledge on new controls. The chapter shows how to implement client side event handlers and how to add and remove event handlers on-thefly. Finally, you will put your knowledge to work by buildingatabbed interface that displays a breadcrumb trail as the mouse hovers each tab.
RadRotator
This chapter explores the RadRotator control and some of the ways it can display a stream of changing content.
AJAX
In this chapter we take a tour of the AJAX related RadControls, paying particular attention to the powerful and flexible RadAjaxManager. You will build a simple AJAX-enabled application that first uses RadAjaxPanel, then substitutes RadAjaxManager to see how the two mechanisms contrast. You will also leverage RadAjaxLoadingPanel to provide better user feedback during AJAX requests. You will learn how to define AJAX settings programmatically at run-time andat design-time using the RadAjaxManager Property Builder dialog to configure settings. Later you will use RadAjaxManagerProxy to perform the same settings configuration within a user control. In this chapter you will build an application that "deals" cards to demonstrate how AJAX requests can be triggered on the client and handled on the server. You will code client-only functions to access common RadAjaxManager properties, e.g. configuration settings, enabling AJAX, canceling requests. You will also handle RadAjaxManager client events that let you set and restore state at the beginning and conclusion of AJAX requests. The chapter also looks at design decisions regarding AJAX-enabling applications. In theprocess we will take a walk through the ASP.NET page lifecycle and its impact on dynamically created user controls, and finally put this information to use in a Winform-like UI demonstrating dynamic user controls together with AJAX. You will see how RadAjaxManagerProxy provides visibility to RadAjaxManager settings in complex container-ship scenarios. Finally, you will see how RadScriptBlock and RadCodeBlock handle common script + markup related issues.
Skinning
Learn how to use built-in skins to provide a coherent,consistent style to your applications. The chapter explores the general makeup of the skin CSS files and how the styles interact with the controls rendered in the
Databinding
This chapter introduces the interfaces that RadControls can bind to and the task specific Data Source controls that can be used to bind declaratively. You will builda simple declarative data binding example using RadToolBar with SqlDataSource. This chapter covers in more detail how the data binding properties are used and how to bind to multiple data sources at one time. In server-side code you see how simple arrays and lists, hierarchical data, business objects and LINQ data are bound. You will also handle data binding related server events.
Templates
This chapter shows the general techniques for working with templates as used by RadControls. First you will build a simple application that uses templates and data binding to elements within the templates. We will explore the details of binding expressions, starting with public server methods and working through Container, DataItem, Eval() and Bind() methods. You will also learn how to find controls within templates using both server and client code.
RadComboBox
This chapter examines the RadComboBox control and the powerful features it provides. You will create a simple application that populatesone combo box with statically declared items and another with items loaded from a data source. The chapter will review the design time support for the combo box and explore many of the properties and groups of properties you can use to configure the combo box at design time. You will learn about the different types of templates you can use with a combo box, and how to work with combo box custom attributes. You will also learn about the load-on-demand mechanism and how it can be used with virtual scrolling or a "More Results" box to improve performance. The chapterreviewssome of the server-side properties and methods, especially those for working with the items in the drop-down list. You will look at some of the important server-side events, such as responding to selected text changes or that service the load-on-demand mechanism. The chapter also covers when and how to sort the drop-down list in server-side code. You will explore some of the client-side methods for working with the items collection, and use important client-side events, including those for responding to selection changes, opening and closing the drop-down list, and the events surrounding the load-on-demand mechanism. Finally, you will learn some advanced techniques, including implementing custom sort criteria, keeping the drop-down list open when an item template includes input controls, controlling when the load-on-demand mechanism fetches items, enabling virtual scrolling when not allowing custom text, and creating a Web service for loading items on demand.
RadTreeView
This chapter reviews the very usefull RadTreeView control and how it lets you you can add the functionality of a desktop tree view to your Web applications. You will create a simple application that populates a tree view with statically declared items and another with items loaded from a data source. In the process you will become familiar with important tree view and tree node properties. We will look at design time support for the tree view andreview many of the properties and groups of properties you can use to configure the tree view and its nodes at design time. You will discover how to use special features of RadTreeView, including node editing, check boxes, drag-and-drop, and node context menus. You will learn some of the server-side properties and methods, and will how to propagate changes to all ancestors or descendants of a node. You will build a node hierarchy dynamically in server-side code, and see how this can be used to populate a tree view with data from multiple tables. You will also learn about several of the tree view server-side events.
RadGrid
This chapter explores the versitile and powerful RadGrid control. You will create a simple application that binds the grid to live data and manipulates the auto-generated columns. You will also explore the most fundamental features of the RadGrid such as Sorting, Filtering, Grouping andPaging. You worked with an example of implementing add, edit and delete operations manually in server-side code. You will learn how to access data values and manipulate the appearance of a columnin server-side code,implement powerful new client-side databinding feature of the RadGrid and finally, use advanced clientside coding techniques, including accessing data values, manipulating appearance and binding to client-side events to make a responsive and flashy interface.
RadEditor
In this chapter we explore RadEditor's rich feature set, learn how to configure RadEditor for the runtime environment and look at the editor's design-time interface. You will learn how to manipulate RadEditor using client-side code including how to reference the editor, the document and the current selection, as well as responding to editor client events. Finally, you will learn some of the editor's customization possibilities, how to optimize RadEditor for multiple instances and how to localize RadEditor for a specific language.
RadChart
This chapter explores the rich functionality and data presentation capabilities of the innovative RadChart control. In this chapter you will build a simple chart with static items and also learn how to bind data to the chart. We will take a tour of the basic RadChart elements as well as the types of charts that are available. You will use the tools in the designer to help navigate the many RadChart capabilities. You will also learn about some of the latest RadChart features, including zooming and scrolling. You will create and configure many of the chart elements programmatically, including the chart series, items, legend and chart title. You will also learn how to bind to database data and respond to events on the server side.
Database Maintenance
In this chapter you will build maintenance functionality for categories, questions and exam related tables. You will use RadGrid heavily to leverage its powerful CRUD handling abilities, creating both master-detail in a single grid and in two related grids. You will use RadControls within a standard ASP.NET FormView along with Eval() and Bind() binding expressions. You will also build a user control that combines RadComboBox with RadTreeView for reuse throughout the application.
User Functionality
In this chapter you will build functionality for the central purpose of the application, the taking of exams. The work is heavily weighted to the client where you will consume a web service to bring back the exam data, use your own JavaScript objects to encapsulate the exam,navigatethrough the exam and summarize the exam results. You will bind a client exam responses object directly to the RadGrid using client code only. You will also use LINQ to SQL within the web service to consume Exam database data.
Exam Scheduling
In this chapter you will implement the scheduling for ActiveSkill. You will learn how to configure RadTreeView and RadScheduler for drag and drop, how to handle scheduler events to create new appointments and modify the attributes of existing appointments based on commands set within the appointment template. You will also learn how to format appointments as they are created based on the logged in user role and appointment attribute data.
Input Controls
The input controls make it easy to collect information from users, whether it is generic text or typed data such as numbers and dates. You can choose from several types of input controls, RadTextBox, RadMaskedTextBox, RadNumericTextBox and RadDateInput. Extensive support for built-in and custom masks make it easier for your user to make valid entries.
RadRotator lets you display and scroll images and data vertically or horizontally, either as a continuous stream
RadAjax
The RadAjax family of controls let you instantly AJAX-enable your application with little programming and configuration effort on your part. RadAjaxPanel AJAX-enables everything that sits on the panel and is an easy way to get started. For more control and potential performance benefit, RadAjaxManager lets you AJAX-enable specific parts of your application. Both routes let you display a "spinny" graphic during long running processes using the RadAjaxLoadingPanel. With RadAjax controls you can get startling performance and thatwindows desktop look-and-feel.
RadComboBox
RadComboBox is an amped up version of a standard drop down list that lets you add images, animated effects, and is templated for complete control over the layout. Unlike the ASP.NET DropDownList control, which restricts users to selecting only items from the list, RadComboBox can optionally allow users to type in their own entries. RadComboBox also works well for very long lists of items. The auto-complete feature automatically scrolls the list and highlights matches, or you can use the filtering capability to limit items to currently entered text. You can even configure the combo box to load on demand.
RadGrid
RadGrid for ASP.NET AJAX is the fastest and most feature-rich Datagrid for ASP.NET, designed to provide desktop-like user experience with minimum HTML output. RadGrid provides real-time performance as well as almost codeless development experience for a rich variety of features.
10
RadEditor
RadEditor is a powerful but lightweight editor control you can use in your web applications where you need an full-featured editor. It comes loaded with lots of built-in goodies like pre-defined buttons, drop down lists and context menus that perform any tasks you are likely to need. If the built-in tools don't fill the bill, RadEditor can be extensively customized.
RadChart
RadChart is a powerful business data presentation tool that can show your data off with striking impact. RadChart comes with many customizable chart types and skins to tailor the behavior and look of each chart. You can choose fine-tune control over all aspects of your chart or use the automatic layout, automatic text wrapping and intelligent labeling functions to handle the details. At design time you get quick access to critical properties with the Smart Tag, convenient groups of important properties in the RadChart wizard, or control all RadChart settings from the Properties Window.
11
12
13
Navigation Controls
2.1 Objectives
Inventory the "navigation" related RadControls. Explore how and where these navigation controls are used. See how each of the navigation controls are similar so you can leverage the same knowledge with each control. Create a simple application to get confidence in using each of the controls. Explore the design time interface for each of the navigation controls, again taking special notice of where the controls are similar. You will learn how to access properties and methods through Smart Tag, Properties Window and Property Builder. Explore principal properties and groups of properties where 80% of the functionality is found. Learn server-side coding techniques, starting with an exploration of important methods and events. You will also learn how to perform common server-side tasks (e.g. add/edit/delete items in a collection) and control-specific tasks (e.g. set a context menu target).
2.2 Introduction
Go to any popular web site and you expect to see menus and tab strips across the top and along the sides. Traversing web pages is after all the bread-and-butter of many web sites. For web applications that mimic full featured Windows applications you expect to see Outlook-like panel bars for organizing functionality, tool bars for taking direct actions and context menus for making intuitive choices within the user's own data. RadControls have you covered with a versatile set of navigation controls for building compelling user interfaces easily:
RadMenu
RadMenu is an advanced navigation control that allows you to build lightweight and search-engine-friendly menu systems. Menus can be displayed horizontally or vertically and have multiple levels.Child items can open up (as shown in the screenshot below) or can automatically scroll.
Menu items can display text, images or both. And because RadMenu items can be templated, you can add virtually any content that suits your purpose:
RadContextMenu
14
RadTabStrip
Use RadTabStrip to build tabbed interfaces for URL navigation or making choices based on tab selection.RadMultiPage is a related controlthat manages content of pages that can be automatically selected by RadTabStrip. Tabs can be located on the top or bottom (see screenshot below), left or right side of your web page.
RadTabStrip has a number of options for customizing layout and appearance including:
Tabs can be aligned left, center, right or justified. Tabs can appear on multiple rows and can "break" at any tab to form a new row. Tabs can scroll for better management of your screen real-estate.
15
Tabs can be structured in a hierarchy for more complex relationships (see screenshot below).
RadPanelBar
Use RadPanelBar to create collapsible vertical menus or Outlook style panels. You can use templates to createa tool bar or simple entry formarea within panels.RadPanelBar can be configured to open only one panel at a time, or multiple panels at one time.
RadToolBar
Tool strips are used in most web applications to allow quick access to common tools. RadToolBar mimics the flexibility of desktop toolbars which can be floating, dockable, re-orderd and can be oriented vertically or horizontally. RadToolBar can be used in conjunction with RadDock to creating a docking toolbar:
16
Uses "semantic rendering" for minimal HTML markup. Semantic rendering avoids costly HTML tables and instead uses Cascading Style Sheets (CSS) to handle appearance and placement. The HTML output is significantly reduced resulting in dramatic performance improvement. Can be populated at design-time, inmarkup, through data binding, in server code or in client code. You can jump ahead to the chapter on Data Binding for detailed information on hooking up all kinds of database and object data to your RadControls. Can be skinned for a great visual appearance that's consistent with your entire web application. Each control comes with a standard set of matched skins (e.g. "Outlook", "Vista", "Black", "Telerik", etc.) that can be simply selected from a list or you can create your own custom skin. You can skip ahead to the chapter on skinningfor details on building your own custom skins. Includes full keyboard support for navigating and activating items. Right-to-left support to allow your application to be internationalized. Except for the tool bar, the navigation controls can be animated so that visual actions such as menu expansion uses one of several predefined effects. Animation can be disabled. Delayand duration for the animation effect can be specified in milliseconds. Each item has a special Attributes collection that can contain any custom name/value pairs you might need. Attributes can be defined declaratively and accessed in code (either client or sever-side). Includes a rich, consistentclient-side API for adding/deleting items on-the-fly, locating/changing items and monitoring events. All these tasks can be performed with best performance right on the client browser. Supports templates so that portions of your RadControl can contain any arbitrary arrangement of HTML including ASP.NET controls, RadControlsor anything else that can be entered into markup.
17
18
19
20
21
Smart Tag
The Smart Tag provides easy access to frequently needed design tasks.To display the Smart Tag, click the small left-pointing arrow located in the upper right of the control or choose "Show Smart Tag" from the context
22
Tasks
Choose Data Source lets you bind the control declaratively by selecting a data source from a drop-down list of all available ASP.NET 2.0 data source components. You can also select <New Data Source...> to display the standard Windows Data Source Configuration Wizard. Build displays an Item Builder dialog where you can create and configure statically defined items for your navigation control.
Ajax Resources
Add RadAjaxManager... adds a RadAjaxManager component to your web page and displays a RadAjaxManager configuration settings dialog. Replace ScriptManager with RadScriptManager swaps out the standard ScriptManager for a RadScriptManager. RadScriptManager is not required for RadControls for ASP.NET AJAXbut does include the ability to combine scripts for greater efficiency. Add RadStyleSheetManager adds a RadStyleSheetManager component to your web page. RadStyleSheetManger combines style sheets to reduce page load time and traffic.
Skin Use the Skin drop-down to preview and select built-in skins. Learning Center Navigate directly to examples for the control, find help or use the code library. You can also search the Telerik
23
Property Builder
Each of the navigation controls displays a Property Builder dialog specific to that control. Display the builder dialog either from the Smart Tag or clicking the Items property ellipses in the Properties Window (the property is called Tabs for the RadTabStrip). The property builder will look substantially the same for all controls except RadToolBar. RadMenu, RadPanelBar and RadTabStrip all support hierarchies of multiple levels, while RadToolBar has an relatively flat structure. Below is a screen shot of the property builder for RadTabStrip items.Use the buttons on the upper left to add root and child level items. You can use the button labeled "Promote" shown below to make a child item a sibling of its parent. Use the "demote" button to make an item a child of the preceding sibling. To edit the text of an item in-line, select it with the mouse, then click it a second time. You can select any of the items and set item properties using the list on the right of the dialog. Typically, you will set the Text property first.
24
The RadToolBar Item Builder has an essentiallyflat structure although a second level of buttons is allowed for drop down and split buttons. RadToolBar does not have an unlimited number of levels and so does not have promote or demote buttons. Also, there are several types of buttons you can add:
RadToolBarButton: Executes some immediate command, or can be configured to have a state and work like a check box or radio button. You can add RadToolBarButton as a root level item or add it under a drop down or split button. RadToolBarDropDown: This button acts as a drop down list of commands when clicked. RadToolBarSplitButton: This button acts much like the RadToolBarDropDown, but has a default command, i.e. the last button in the list you clicked. The split button works well when one of the commands is used all of the time.
25
The resulting tool bar running in the browser looks something like this:
Properties Window
The superset of properties available to the control are found in the Properties window. We will use the 80/20 rule here, that is, locate the most important properties and groups of properties common between navigation controls that are used constantly.
26
The single most important property of the navigation controls is the Items collection (or Tabs in the case of RadTabStrip). Items make up the content of the navigation control. You can populate your navigation control items...
Statically, using the Items property or using the Item Builder dialog. Defining items in the ASP.NET markup. For example, the ASP.NET fragment below shows RadMenu with two levels of items defined. [ASP.NET] Defining RadMenu Items <telerik:RadMenu ID="RadMenu1" runat="server" > <Items> <telerik:RadMenuItem runat="server" Text="File"> <Items> <telerik:RadMenuItem runat="server" Text="Exit"> </telerik:RadMenuItem> </Items> </telerik:RadMenuItem> <telerik:RadMenuItem runat="server" Text="Edit"> <Items> <telerik:RadMenuItem runat="server" Text="Cut"> </telerik:RadMenuItem> <telerik:RadMenuItem runat="server" Text="Copy"> </telerik:RadMenuItem> <telerik:RadMenuItem runat="server" Text="Paste"> </telerik:RadMenuItem> </Items> </telerik:RadMenuItem> </Items>
27
Adding programmatically on the server or client side.We will cover the details in the server and client side programming sections upcoming. Data Binding. We will cover data binding thoroughly in a later chapter. For now, know that the data binding specific properties are:DataSource, DataSourceID, DataMember, DataTextField, DataTextFormatString, DataValueField andAppendDataBoundItems. Multi-level hierarchiesare implemented (for navigation controls other than RadToolBar) with the use of DataFieldID, DataFieldParentID and MaxDataBindDepth properties. Also, all navigation controls other than RadToolBar have a DataNavigateUrlField that lets you bind to a column that contains a URL.
Eachitem within the Items collection has its own set of properties. Text is the string that displays in the UIfor an item, ImageUrl is a path to an image file that will display next to the Textand NavigateUrl is a URL that will be navigated to when the item is clicked. With just these three properties alone, you can do quite a bit of web site building. Use the NavigateUrl property together with Target to specify the target window or frame to display the NavigateUrl web page content. Target can be specified as _blank (target URL will open in a new window), _self (target URL will open in the same frame, _parent (target URL will open in the parent frameset) and _top (target URL will open in the topmost frame). If your purpose is not to navigate URLs, but to make choices within a web application, the Value property is a useful place to store codes, record IDs or any arbitrary string. The Value can be retrieved in both client and server code. Tocraft the look of individual items, look for property namesending in "ImageUrl". Depending on the particular item type you will see DisabledImageUrl, ExpandedImageUrl, HoverdImageUrl, SelectedImageUrl, etc.Also look for properties ending in "CssClass". These properties specify CSS classes used to style the item during particular states, e.g. ClickedCssClass, DisabledCssClass, ExpandedCssClass, FocusedCssClass, etc. Some of these classes may be pre-populated with class names from the control's skin (see the chapter on Skinning for details on working with RadControls skins). Use separators to visually group items into two or more categories. Set the IsSeparator property of an itemto true; that item will not respond to user clicks or keyboard actions. The RadMenu screenshot below shows a separator defined for an item between the "Save" and "Exit" items.
The markup for this example looks like this: [ASP.NET] Using IsSeparator <telerik:RadMenuItem runat="server" Text="File"> <Items> <telerik:RadMenuItem runat="server" Text="New"> </telerik:RadMenuItem> <telerik:RadMenuItem runat="server" Text="Open"> </telerik:RadMenuItem> <telerik:RadMenuItem runat="server" Text="Save"> </telerik:RadMenuItem> <telerik:RadMenuItem runat="server" IsSeparator="True" Text="My Separator"> </telerik:RadMenuItem> <telerik:RadMenuItem runat="server" Text="Exit"> </telerik:RadMenuItem> </Items>
28
Create an item instance for the particular type of collection. Populate the instance properties. Add the item to the Items collection.
When you add to the Items collection and type in the open parenthesis, IntelliSense will display code completion with the specific item type (or press ctrl-shift-spacebar to invoke IntelliSense.
Notice that the RadMenuItem type in the screenshot above is in the Telerik.Web.UI namespace. Save some time and typing effortbyadding a using statement to include this reference. The remainder of this courseware will assume that you have included the Telerik.Web.UI namespace. The example below uses a ScriptManager (or RadScriptManager), a RadAjaxManager and a RadMenu. The RadAjaxManager has a nifty little Alert() method that automatically pops up a client-side alert dialog. You can skip ahead to the chapter "AjaxPanel, AjaxManager and AjaxProxy" for an exploration of these important components. In the Page_Load event handler, two RadMenuItem instances are created. The first RadMenuItem is assigned Text, NavigateUrl and Target properties, then added to the RadMenu.Items collection. The Target property is set to "_blank" so that a second browser will pop up. Gotcha! When you populate the NavigateUrl property, be sure to type the entire URL including the "http://" and avoid the "Resource not found" error.
The second RadMenuItem is not given a NavigateUrl but instead gets a Value property. Finally, the ItemClick event handler is hooked up. When the user clicks the first item, a second browser window pops up to display the Telerik web site. When the second menu item is clicked, a JavaScript alert dialog displays "The value for clicked item is: 123". Find the code for this project in \VS Projects\Navigation\ServerSide. [VB] Adding Items Imports Telerik.Web.UI Namespace ServerSide Public Partial Class _Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not IsPostBack Then ' 1) create the item instance Dim menuItem As New RadMenuItem()
29
30
31
You can find sample images to work with in the Visual Studio 2008 directory: \Microsoft Visual Studio 9.0 \Common7\VS2008ImageLibrary\1033\VS2008ImageLibrary.zip The example populates the ImageUrl property using image paths within the project. First the Edit item is
32
Deleting Items
To delete an item, call the navigation control Remove() method and pass the item object to be deleted, or call RemoveAt() and pass the index of the item to be removed. The example below shows two different ways to remove the first item in the collection. [VB] Deleting an Item RadToolBar1.Items.Remove(RadToolBar1.Items(0)) RadToolBar1.Items.RemoveAt(0)
33
Locating Items
Each navigation controls Items collection comes with a rich set of server-side methods for locating items. All three methods pass back an item instance of found (e.g. RadMenuItem, RadPanelBarItem, etc) or null if not found.
FindItemByText(string text): Pass a string that matches the Text property of an item. FindItemByValue(string value): Pass a string that matches the Value of an item. FindItemByAttribute(string attributeName, string value): This one is a little tricker. You can add arbitrary attributes to an items markup and this method searches by the name and value of the attribute. For example, you could give a RadMenuItem a custom attribute and value, for example 'Category="Clothing". then call FindItemByAttribute("Category", "Clothing").
You can find this next project at\VS Projects\navigation\ServerLocatingItems. The example uses a RadToolBar to initiate the find, looking for items in a RadPanelBar byText, Value and Attribute. Items are then expanded,hidden and disabled. The screenshots below show the before and after state of the PanelBar.
Review the markup below and notice that each PanelBar item is populated with Text, a unique Value and a "Priority" attribute. The custom attribute "Priority" may be "Low", "Medium" and "High". Also notice that the RadToolBar has an OnButtonClick event handler defined. [ASP.NET] PanelBar Items Markup <telerik:RadToolBar ID="RadToolBar1" Runat="server" onbuttonclick="RadToolBar1_ButtonClick" Skin="Outlook" Width="155px"> <Items> <telerik:RadToolBarButton runat="server" ImageUrl="~/Images/FindHS.png" Text="Find"> </telerik:RadToolBarButton> <telerik:RadToolBarButton runat="server" ImageUrl="~/Images/DeleteHS.png" Text="Delete"> </telerik:RadToolBarButton> </Items>
34
35
First we need to get all items, not just root level items for a given Items collection. To do this, call the navigation control's GetAllItems() method. This will return a generic IList collection containing all items, at all levels. You can then iterate your Ilist and perform operations on each item. [VB] Deleting Items
36
37
The order of tabs is "depth first", that is, the children of the first tab are before the second root level tab. If there are more page views than tabs, the last page views are ignored. If there are more tabs than page views, the last tabs do not display a page view.
5. From the RadMultiPage Smart Tag, select the "Add RadPageView" link twice. RadMultiPage starts with a single PageView by default, so you should have three PageViews at this point.
38
8. In the designer, drop a RadColorPicker into the first PageView, a RadCalendar control to the second PageView and enter the quote "You can observe a lot by watching - Yogi Berra" directly into the last PageView. Set the Skin property for the RadCalendar and RadColorPicker to "Black". In addition, set the Width property of RadColorPicker to "220px" and Preset property to "Standard". 9. Press Ctl-F5 to run the application.
That's a lot of functionality from just dragging and dropping. But be aware that all the content is present on the page whether its visible or not. For better performance and scalability, larger applications will need to bring in content dynamically. We will talk aboutone way todo this with AJAX anduser controlsin the upcoming "AjaxPanel, AjaxManager and AjaxProxy".
39
6. In the Properties window for the RadContextMenu, select the Events button anddouble click the ItemClick event to create an event handler. Add the following code to the ItemClick and the Page_Load event handlers: [VB] Handling the Page_Load and ItemClick Events Imports Telerik.Web.UI Namespace MultiPage Public Partial Class _Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not IsPostBack Then ' get the parent menu item
40
41
2.7 Summary
In this chapter you took a tour of the "navigation" related RadControls and became familiar with how and where each of these controls are used. You saw some of the important properties, methods and events that arecommon between navigation controls. You created a simple application that used the menu, tab strip and tool bar controls. You learned some common server-side tasks such as add/edit/delete, iterating items in a
42
43
Input Controls
3.1 Objectives
Inventory the "input" related RadControls. Explore how and where these input controls are used. See how each of the input controls are similar so you can leverage the same knowledge with each control. Create a simple application to get confidence in using each of the controls. Explore the design time interface for each of the input controls, again noting where the controls are similar. You will learn how to access properties and methods through Smart Tag, Properties Window and control-specific dialogs. Explore principal properties and groups of properties where 80% of the functionality is found. Learn how to perform common server-side tasks such as creating controls dynamically, setting values, and responding to changed values. Learn how to perform common client-side tasks such as enabling and disabling, restricting input as the user types, and handling parsing errors. Learn to use the input controls with other controls such as RadSpellCheck or ASP.NET validator controls.
3.2 Introduction
Often, you want to create a Web application that collects data from the users who visit your Web site. This data can be anything from details for shipping and billing, to an elaborate survey form. RadControls make it easy to collect information from users, whether it is generic text or typed data such as numbers and dates. You can choose from several types of input controls, depending on what type of data you want users to enter:
RadTextBox
RadTextBox is a highly configurable input control that lets users enter arbitrary text values. Users can enter any type of character into RadTextBox (alphabetic, numeric, and symbols). RadTextBox supports three different modes: Single-line mode lets users enter short values that fit on a single line.
Multi-line mode lets users enter longer values that can take up several lines:
Password mode hides the characters that users type so that it can be used for entering sensitive information such as passwords:
From Q2 2011 on the RadTextBox control offers a password strength checking feature. The same can be used inside a TextBoxSetting created with a RadInputManager. The feature allows you to specify your custom criteria for password strength and visualize an indicator to inform the user how strong is the typed password according to this criteria.
RadMaskedTextBox
44
RadNumericTextBox
RadNumericTextBox restricts users to entering numeric values. This control supports a wide variety of formatting options; you can rely on the local culture setting to format number, currency, or percentage values, or you can supply your own detailed formatting specifications.
While users can always type numbers into RadNumericTextBox, you can also let them change the current value by simply incrementing or decrementing it. You can let users increment or decrement the current value in any or all of the following ways:
Spin buttons can be added to the right or left of the input area. Mouse wheel support can be enabled to let users change the value using the mouse wheel when the numeric text box has focus. Arrow key support can be enabled to let users change the value using the up and down arrow keys.
RadDateInput
Use RadDateInput to let users enter date and time values. RadDateInput is a free-form date and time input control. That is, it has a built-in parsing engine that can recognize date and time values in a wide variety of valid formats, so that you do not need to restrict users to a limited format in order to interpret values. The parsing engine is culture-sensitive, so that you can easily localize your Web application. Like RadNumericTextBox, RadDateInput lets you control how values are formatted for display. You can specify the format using standard ASP.NET date and time format strings. You can also set the culture to control how RadDateInput interprets the culture-specific parts of those format strings (such as the names of months or days).
Also like RadNumericTextBox, you can let users increment or decrement the current value by enabling mouse wheel or arrow key support. (You can't add spin buttons to RadDateInput, however.)
Common Features
Each of the input controls...
Supports interaction with the clipboard, including built-in shortcut keys for cut, copy, and paste. Displays a built-in context menu when the user right clicks to invoke common editing tasks such as
45
Can be skinned for a great visual appearance that's consistent with your entire web application. You can choose from a standard set of matched skins (e.g. "Outlook", "Vista", "Black", "Telerik", etc.) or you can create your own custom skin. Lets you add an integrated label and/or button on the left or right of the input area. (On RadNumericTextBox, you can also add a set of spin buttons). Supports tool tips that can give the user additional information about the value to be entered. Lets you specify the position of the caret and whether the text is selected when the input control gets focus. This lets you control how the value changes when the user first starts typing. Distinguishes between edit mode (when the control has focus) and display mode. Except for RadTextBox,you can specifydifferent formatting options for edit and display mode. In display mode, you can also specify a string that appears when the value has not yet been set (even for RadTextBox). Can be set to ReadOnly mode when you want to use it for display purposes only. Supports limitations on the range of valid values. The type of range depends on the type of input control: RadTextBox lets you set the maximum length; RadMaskedTextBox lets you specify a range on parts of the mask; RadNumericTextBox and RadDateInput let you specify minimum and maximum values. Includes a rich, consistent client-side api for managing the value range, selection, and caret position of the input control, as well as a wide range of client events for responding to client input quickly on the browser without the need for postbacks. Can be optionally set to trigger postbacks when the value changes and to trigger ASP.NET validation of other controls on the page when that postback occurs.
46
4. In the Appearance section of the Properties Window, set the Label property to "Phone: ". 5. In the Behavior section of the Properties Window, set the EmptyMessage property to "- Enter phone number -" and the HideOnBlur property to True. Because the Mask property is set, the masked text box displays the mask when no text has been entered. By setting the HideOnBlur property, you cause the masked text box to show the value of EmptyMessage instead when the control is in display mode. 6. Set the SelectionOnFocus property to "CaretToBeginning" and the ToolTip property to "Phone number of contact."
47
4. In the Smart Tag again, click the Set Date Format link to bring up the Date Format Dialog again. This time, the date format is for edit mode. Select the row for the short date format ("d") and then hit OK:
48
5. In the Appearance section of the Properties Window, set the Label property to "Ship by: ". 6. In the Behavior section of the Properties Window, set the EmptyMessage property to "- Enter the ship by date -", the ToolTip property to "The last date the order can be shipped." and the SelectionOnFocus property to "SelectAll".
49
You have already seen the Ajax Resources, Skin selection, and Learning center when looking at the Smart Tag for the navigation controls. This time, we will just look at the Tasks that are specific to the individual input control types. Tasks The top portion of the Smart Tag for each type of input control lists a different set of tasks you can perform. The RadTextBox Smart Tag lists two tasks at the top:
Text lets you set the initial value of the text box. Any string you enter here appears in the input area as the value of the text box, which the user can subsequently edit. Empty Message lets you specify a message that appears in the input area when no value has been set. Using an empty message is a convenient way to provide a prompt to the user about what data should be entered or to provide feedback that the value has not been set (as distinct from a value that is set to an empty string).
The RadMaskedTextBox Smart Tag lists only one task at the top, but it is an important one:
Set Mask brings up the Input Mask Dialog, where you can assign the mask that the text box uses to restrict input. This dialog is described in more detail below. When you assign a mask using the Set Mask option, the mask you assign controls the data the user can enter and the way it is formatted. By default, this mask
50
Numeric Type lets you specify the type of numeric value that the numeric text box is to represent. This can be Number, Currency, or Percent. The numeric type affects the way the value is formatted when the numeric text box is in display mode. (In edit mode, the number is always formatted as a number only.) Value lets you specify the initial value of the numeric text box.
Set Display Date Format brings up the Date Format Dialog, where you can specify the format string that is used in display mode. Set Date Format also brings up the Date Format Dialog, but this time the format string you specify is used to format the value when the text box has focus (when the user is editing its value). If you specify this format string, but not a display date format, this string is always used to format values, even when the text box does not have focus.
Properties Window
All of the properties available to the control are found in the Properties window. As before, we use the 80/20 rule here; that is, locate the most important properties and groups of properties of the input controls.
Properties for the value Probably the most important property of any input control is the one that holds its value. While you may not always want to initialize this property at design time, you will certainly want to read the value that the user
51
RadTextBox uses the Text property. RadMaskedTextBox is a little more complicated, because you may want to consider several values: with or without the literal characters of the mask, and with or without the prompt characters in the mask. As a result, there are four separate properties for the value:
Text is the value without any prompt characters or literal characters from the mask. This is the value you can set to provide an initial value. TextWithPrompt is just what the name implies: the text plus prompt characters for any un-entered parts of the mask, but without literal characters from the mask. It is read-only. TextWithLiterals is the text plus the literal characters from the mask (but no prompt characters). This is not read-only, so that the control can be data-bound to a source that stores values which include literals. TextWithPromptAndLiterals has the text, plus prompt characters and literal characters from the mask. This is again read-only.
RadNumericTextBox uses the Value property for its value. Value is a double rather than a string, so that your application does not need to worry about converting the value. If you are using the numeric text box as part of a data-bound custom control, you can use the DbValue property instead, so that the control can handle null values. RadDateInput uses the SelectedDate property. SelectedDate is, of course, a DateTime value. Like the DbValue property of RadNumericTextBox, RadDateInput has a DbSelectedDate property that can handle null values.
Properties for common features The four types of input control have a lot of features in common, and these are reflected by a common set of properties. The EmptyMessage property, which we have already encountered on the RadTextBox Smart Tag, is available for all four types of input control. For RadMaskedTextBox, however, this property only has an effect if the HideOnBlur property is set to true. Other important properties include ToolTip, which lets you supply a message that appears when the mouse hovers over the control, Label, which lets you supply a text label that appears to the left of the input area, SelectionOnFocus, which determines the default placement of the caret and selection of text when the control gets focus, and ReadOnly, which lets you limit the control to display mode. Both RadTextBox and RadMaskedTextBox let you set the InputMode property to SingleLine, MultiLine, or Password. When InputMode is MultiLine, the Rows and Columns properties determine the number of rows displayed, and the number of characters in each row. The Wrap property specifies whether text wraps when it exceeds the number of characters specified by Columns, or whether the control only honors line breaks and uses scroll bars for long lines. RadNumericTextBox and RadDateInput let you set the IncrementSettings property to specify how the user can increment and decrement values. This is a composite property, with sub-properties for enabling arrow keys or mouse wheel, and for specifying the step size for each increase or decrease. Properties governing look-and-feel Like most RadControls, you can use the Skin property to set the general appearance of the input controls to match the other controls in your Web application. Predefined skins can be selected from a list or you can skip ahead to the chapter on skinning for details on building your own. You can further craft the appearance of your input control for when it appears in different states by using the various "Style" properties. These include EnabledStyle, DisabledStyle, EmptyMessageStyle, FocusedStyle, HoveredStyle, InvalidStyle, and (in the case of RadNumericTextBox) NegativeStyle. Also look for properties
52
53
As shown in the preceding screen shot, you can choose from a selection of pre-defined masks. Just click on the row for a mask and the mask string automatically appears in the Mask text box, with a preview to show the prompts and literals below it. You can modify the pre-defined type by editing the string in the Mask text box. You can also define your own mask string from scratch by selecting the row labeled <Custom> and typing in a mask string. The preview updates as you type. The mask string is made up of one or more parts, where each part represents a single (possibly optional) character or a value selected from a numeric range or set of enumerated strings. The following table lists the mask characters that correspond to each type of mask part: Description Accepts a single character. If this position is blank in the a FreeMaskPart text, it is rendered as a prompt character. Uppercase letter (required). Restricts input to the ASCII L UpperMaskPart letters A-Z. Lowercase letter (required). Restricts input to the ASCII l LowerMaskPart letters a-z. Digit or space (optional). If this position is blank in the text, # DigitMaskPart it is rendered as a prompt character. Restricts the user to an integer in the declared numeric <n..m> NumericRangeMaskPartrange. Numeric range mask parts can occupy multiple positions. Restricts the user to one of a fixed set of options. The pipe <Option1|Option2|Option3>EnumerationPart ("|") serves as a separator between the option values. Escape character, allowing the following character to act as literal text. For example "\a" is the character "a" rather than \ N/A including a free mask part. "\\" is the literal back slash character. All non-mask elements appear as themselves. Literals always Any other characters LiteralPart occupy a static position in the mask at run time, and cannot be moved or deleted by the user. Mask Element MaskPart class
54
Use the MaskPart Collection Editor to build up a mask part by part. You can add parts to the mask by clicking the Add Button. Simply clicking the Add button adds a LiteralMaskPart. If you click on the drop-down arrow, you get a list of mask part types and can choose what type of part to add. When a mask part in the collection is selected, the right side of the dialog shows the properties you can set for that type of mask part. In the screenshot above, a Numeric Range is selected, with properties for the maximum and minimum value in the range. You can use the Remove button to remove parts from the mask you are building, and the arrow keys to rearrange the parts you have added. When you click the OK button to exit the dialog, the Mask or DisplayMask property is updated to reflect the new mask you built.
55
In theDate Format Dialog, you canselect from a set of standard format strings by selecting a row in the table. The expanded format string appears in the Custom Date Time Format text box, with a preview to show you how the string formats date and time values. You can then edit the string to get just the format you want, watching the preview update to reflect your changes. RadDateInput uses standard ASP.NET date format strings with one exception: the one-character format strings listed in the table of the Date Format Dialog are always expanded to their constituent parts. As a result, if you change the Culture property, you must re-assign the DateFormat and DisplayDateFormat properties to ensure that the parts of the date format are expanded correctly. The following table lists the format patterns to use when building a date format string: Format Pattern d dd ddd dddd M MM MMM MMMM y yy yyy gg h hh H Description The day of the month. Single-digit days have no leading zero. (Only if used in the context of a longer pattern. A single "d" on its ownrepresents the Short date pattern.) The day of the month. Single-digit days have a leading zero. The abbreviated name of the day of the week. The full name of the day of the week. The numeric month. Single-digit months have no leading zero. (Only if used in the context of a longer pattern. A single "M" on its own represents the Month day pattern.) The numeric month. Single-digit months have a leading zero. The abbreviated name of the month. The full name of the month. The year without the century. If the year without the century is less than 10, with no leading zero. (Only if used in the context of a longer pattern. A single "y" on its own represents the Month year pattern.) the year without the century. If the year without the century is less than 10, with a leading zero. The year in four digits, including the century. The period or era (e.g. "A.D."). This pattern is ignored if the date to be formatted does not have an associated period or era. The hour in a 12-hour clock. Single-digit hours have no leading zero. The hour in a 12-hour clock. Single-digit hours have a leading zero. The hour in a 24-hour clock. Single-digit hours have no leading zero.
56
The hour in a 24-hour clock. Single-digit hours have a leading zero. The minute. Single-digit minutes have no leading zero. (Only if used in the context of a longer pattern. A single "m" on its own represents the Month day pattern) The minute. Single-digit minutes have a leading zero. The second. Single-digit seconds have no leading zero. (Only if used in the context of a longer pattern. A single "s" on its own represents the sortable time pattern.) The second. Single-digit seconds have a leading zero. The first character in the AM/PM designator. (Only if used in the context of a longer pattern. A single "t" on its own represents the short time pattern.) The AM/PM designator.
Set the AutoPostBack property of the input control to true so that a postback occurs when the value of the control changes. Provide a handler for the TextChanged event that responds when the postback occurs.
The following example uses the TextChanged event to dynamically create new input controls based on the values of two input controls: a masked text box to specify the type of control to create, and a numeric text box to specify the number of new input controls to create.
This example uses a full postback for handling the TextChanged event. For a smoother response, you can look ahead to the chapter on AJAXPanel, AjaxManager, and AjaxManagerProxy to see how to handle the event in an asynchronous callback. The masked text box has the mask "<TextBox|MaskedTextBox|NumericTextBox|DateInput>". This ensures that the user can only select one of the four input control types, and that the resulting selection is a known string. The numeric text box has MinValue and MaxValue set to 0 and 9, to limit the range of entries, and a MaxLength of 1 to prevent the user from trying to enter decimal values. The NumberFormat property sets DecimalDigits to 0 so that values are formatted as integers. Both controls have the AutoPostBack property set to true. Because the TextChanged event for all input control types has the same signature, they can share the same event handler. The shared TextChanged event handler reads the values of the masked text box and numeric text box, and dynamically creates new input controls to reflect those values. The new controls are added to a PlaceHolder.
57
58
59
Response-dependent enabling
One common task in input forms is enabling or disabling some questions based on the responses to others. The following example illustrates how this can be done. The example provides a handler for the client-side OnValueChanged event. The OnValueChanged event occurs when the control loses focus after the user edits its value. This example uses OnValueChanged because that event is common to all input control types. You could, instead, use the OnEnumerationChanged event, which is only available on RadMaskedTextBox. The event handler checks the value that a user entered, which is available from the event arguments, and then calls the enable() or disable() method of another control, as appropriate. When disabling, it also calls the clear () method to remove any previously-set value. The code for this project is in \VS Projects\Input\ClientSide. [ASP.NET] Response-dependent enabling <head runat="server"> <title>Response-Dependent Enabling</title> </head> <body> <script type="text/javascript"> function MaritalStatusChanged(sender, eventArgs) { // find the control to be enabled or disabled var dateEnter = $find("<%= MarriageDate.ClientID %>"); // enable or disable the control based on newValue if (eventArgs.get_newValue().trim() != "Single") dateEnter.enable(); else { dateEnter.clear(); dateEnter.disable(); } } </script> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <div>
60
61
62
63
3.7 How To
You can enhance the functionality of RadTextBox by using it in combination with other ASP.NET controls.
The form uses three validation groups: "LoginGroup", "SignUpGroup", and "PWGroup":
The "LoginGroup" validation group is assigned to the two validators in the left-hand panel, and to the button in that panel which triggers validation on postback. Note that no special settings are required on the text boxes; they are validated simply because of the ControlToValidate property of the corresponding
64
The "SignUpGroup" validation group is similar. It checks for required fields in the right-hand panel when the "Sign Up" button triggers a postback. The only thing new here is that this group includes a regular expression validator to check for valid email addresses as well as the required field validators. [ASP.NET] "SignUpGroup" controls and validators <telerik:RadTextBox ID="SignUpName" Runat="server" Skin="Outlook" Width="75%" Label="Name: " ToolTip="Enter a name for your account" > </telerik:RadTextBox> <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="SignUpName" ErrorMessage="You must supply an account name!" ValidationGroup="SignUpGroup"> </asp:RequiredFieldValidator> <br /> <telerik:RadTextBox ID="SignUpPW" Runat="server" Skin="Outlook" Width="75%" Label="Password: " TextMode="Password" ToolTip="Enter the password you want to use"> </telerik:RadTextBox> ... <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" ControlToValidate="SignUpPW" ErrorMessage="You must supply a password!" ValidationGroup="SignUpGroup"> </asp:RequiredFieldValidator> <br /> <telerik:RadTextBox ID="SignUpPWConfirm" Runat="server" Skin="Outlook" Width="75%" Label="Confirm Password: " TextMode="Password" ToolTip="Retype your password to confirm"
65
The "PWGroup" validation group is a little different because it is not initiated by a postback. Instead, validators in this group are checked when the user enters a value in the password confirmation text box.To accomplish this, the password confirmation text box has its CausesValidation property set to true and its ValidationGroup property set to "PWGRoup". When this validation group is checked, a regular expression validator ensures that the password is valid, and a compare validator checks that the confirmation matches. Note that the password confirmation text box is triggering validation on itself. [ASP.NET] "PWGroup" controls and validators <telerik:RadTextBox ID="SignUpPW" Runat="server" Skin="Outlook" Width="75%" Label="Password: " TextMode="Password" ToolTip="Enter the password you want to use"> </telerik:RadTextBox> <asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ControlToValidate="SignUpPWConfirm" ErrorMessage="Password must be 6-10 characters, contain at least one digit and one number, and have no special characters!" ValidationExpression="(?!^[0-9]*$)(?!^[a-zA-Z]*$)^([a-zA-Z0-9]{6,10})$" ValidationGroup="PWGroup"> </asp:RegularExpressionValidator> ... <telerik:RadTextBox ID="SignUpPWConfirm" Runat="server" Skin="Outlook" Width="75%" Label="Confirm Password: " TextMode="Password" ToolTip="Retype your password to confirm" CausesValidation="True" ValidationGroup="PWGroup"> </telerik:RadTextBox> <asp:CompareValidator ID="CompareValidator1" runat="server" ControlToCompare="SignUpPW" ControlToValidate="SignUpPWConfirm" ErrorMessage="Password does not match!" ValidationGroup="PWGroup"> </asp:CompareValidator>
66
The following walk-through guides you through the process of linking up a spell checker with a multi-line text box. The code for this example can be found in \VS Projects\Input\HowToSpellCheck. 1. Create a new ASP.NET Web Application and add a ScriptManager onto the page from the AJAX extensions section of the tool box. 2. Locate the English dictionary that the spell checker uses. This file is called "en-US.tdf", and can be found in the App_Data\RadSpell folder inside the folder where you installed RadControls for ASPNET AJAX. Copy this file and paste it into the App_Data folder of your project (using the Project Explorer). 3. Right-click on your project in the Project Explorer and choose Add|Add ASP.NET Folder|App_GlobalResources from the context menu. 4. Locate the spell dialog resource, "RadSpell.Dialog.resx", in the App_GlobalResources folder inside the folder where you installed RadControls for ASPNET AJAX. Copy this file and paste it into the App_GlobalResources folder that you added in the last step. Your Project Explorer should now look something like the following:
67
5. Add a RadTextBox control to your Web page. Set its Skin property to "WebBlue", TextMode to "MultiLine", Rows to 10 and Columns to 50. 6. Add a RadSpell control to your Web page below the RadTextBox. 7. In the Smart Tag that appears automatically, click the Enable RadSpell Http Handlers link.
8. On the RadSpell control, set the ControlToCheck property to "RadTextBox1" and the DictionaryPath property to "App_Data". 9. Press Ctl-F5 to run the application. You can enter a lengthy value in the text box (with some spelling errors in it). Click the "Spell Check" button to invoke the spell checker. When you exit the dialog, any corrections you made in the dialog are reflected in the text box.
68
ShowIndicator - enables/disables the indication. By default ShowIndicator is set to false. In order to show the indication set the property to true. PreferredPasswordLength - preferred length of the password. MinimumNumericCharacters - the number of minimum numeric characters that the user has to enter in order for his password to be considered as a strong one. MinimumUpperCaseCharacters - the number of minimum upper case characters expected. MinimumLowerCaseCharacters - the number of minimum lower case characters expected. MinimumSymbolCharacters - the number of minimum symbol characters expected. CalculationWeightings - a list of 4 semi-colon separated numeric values used to determine the weighting of a strength characteristic. The total of the 4 values should be 100. By default they are defined as 50;15;15;20. This means that password length will determine 50% of the strength calculation, numeric criteria is 15% of strength calculation, casing criteria is 15% of calculation, and symbol criteria is 20% of calculation. So the format is "A;B;C;D" where A = length weighting, B = numeric weighting, C = casing weighting, D = symbol weighting. RequiresUpperAndLowerCaseCharacters - specifies whether upper and lower case characters are required. By default the property is set to "true". When it is "false", the MinimumLowerCaseCharacters and MinimumUpperCaseCharacters properties do not affect the calculation of the password. IndicatorElementID - sets a div or span element to which the indication will be applied. If this property is not set, such element will be created automatically. IndicatorElementBaseStyle - the name of the CSS class that will be used for styling the indicator element. TextStrengthDescriptions - a list of five semi-colon separated strings which will used as descriptions for the password strength. By default TextStrengthDescriptions is set to "Very Weak;Weak;Medium;Strong;Very Strong". TextStrengthDescriptionStyles - a list of six semi-colon separated CSS classes that will be applied depending on the calculated password strength. By default the property is "riStrengthBarL0;riStrengthBarL1;riStrengthBarL2;riStrengthBarL3;riStrengthBarL4;riStrengthBarL5;"
You can find the complete source for this project at: \VS Projects\Input\PasswordStrengthChecker
69
Loading time - usually, having a large number of input controls on the page, each associated with a separate object and client events and handlers, would imply a performance hit. Introducing the RadInputManager, however, dramatically reduces the load time. Maximum number of controls allowed on the page - local tests showed that with the help of RadInputManager, the number of input controls a standard application would allow can be increased up to ten times. Footprint of the page - local tests showed that a standard page, with a total of 300 input controls, generates a footprint of approximately 400KB. On the other hand, extending 300 standard text boxes via the RadInputManager, to enhance their behavior to a NumericInput control, generates a footprint of approximately 100KB. This brings about faster loading and better responsiveness of the page.
Performance
The core of the performance benefit of using a RadInputManager as opposed to input controls, is in the following approach. A normal input control generates a client side object for each control instance. For example, if you declare 300 input controls on the page, you will have 300 client objects, once the page is compiled and ran. On the other hand, when extending standard text boxes, via the RadInputManager control, you will have a single client side object, which would dramatically improve performance, while at the same time providing enhanced data entry capabilities for user input validation. To summarize, the RadInputManager offers extended functionality to standard text boxes, with little overhead related to increased page footprint, or extra coding.
Design-Time Support
The most important aspect of the design time support for the control is the ability to configure it to determine which controls on the page will be extended through it. Essentially, the approach is similar to the one used to Ajax-enabled controls on the page via the RadAjaxManager. First, you select what type of setting you will be adding - TextBoxSetting / NumericTextBoxSetting / RegExpTextBoxSetting / DateInputSetting.
70
Once you have chosen one of the four possible options, you can choose which particular controls on the page you would like to extend the right-hand side pane lists all the controls on the current page.
After you have chosen the setting, and the controls to be extended, you can set some of the most important properties of each setting, as shown in the screen shot below:
71
The properties which can be set include css classes for the different states (hover/enabled, etc), behavior settings such as BehaviorID and EmptyMessage, as well as the client-side events (OnBlur, OnError, OnFocus, OnKeyPress). The RadInputManager property builder is also available in the Properties window through the InputSettings property.
72
73
A unique id for the settings related to a given text box. The name of the client side function which will be raised when the control loses focus. The name of the client side function which will be called when an error occurs the user enters invalid input. The name of the client side function which will be called when the control receives focus. The name of the client side function which will be called when the user presses a button, while the control has the focus. Gets or sets the date and time format used by RadDateSetting. Gets or sets the display date format used by RadDateSetting (Visible when the control is not on focus). The text which will be displayed before the user has entered any text. Sets the message to be displayed when invalid value is entered. A property which indicates whether the client event handlers and css classes will be set on the client. The minimal date which the user will be allowed to enter. The maximal date which the user will be allowed to enter. A property, which is used to determine whether the text in the control will be selected, once it receives focus. Gets or sets a value that indicates the end of the century that is used to interpret the year value when a short year (single-digit or two-digit year) is entered in the input.
Description A unique id for the settings related to a given text box. The name of the client side function which will be raised when the control loses focus. The name of the client side function which will be called when an error occurs the user enters invalid input. The name of the client side function which will be called when the control receives focus. The name of the client side function which will be called when the user presses a button, while the control has the focus. The text which will be displayed before the user has entered any text. A message which is displayed if the regular expression matching fails. A property which indicates whether the client event handlers and css classes will be set on the client. A property, which is used to determine whether the text in the control will be selected, once it receives focus. A regular expression, representing the matching criteria. The ValidationGroup to which the regular expression setting is assigned.
DisabledCssClass EmptyMessageCssClass
74
Each one of the setting groups also allows for different behavior and contains a BehaviorID property, which is used to identity settings pertaining to a given text box. These can later be retrieved on the client, for example, and access a property such as the EmptyMessage. Note that each input setting must have at least one target control, otherwise it will not be serialized to the client and its client object would not be instantiated.
Give it a try
Set up the project structure 1. Create a new ASP.NET Web Application. 2. In the designer, drag a ScriptManager from the AJAX extensions section of the tool box onto your page. Add the RadInputManager and TextBox controls. 1. Add a RadInputManager to your web page. In the Smart Tag, select "Vista" from the Skin drop-down. 2. Add a TextBox to your web page. In the Misc section of the Properties Window change its ID to "ExtendedTextBox". 3. Add a few line breaks after the TextBox and add a new TextBox to your web page. In the Misc section of the Properties Window change its ID to "ExtendedNumericTextBox". 4. Add a few line breaks after the TextBox and add a new TextBox to your web page. In the Misc section of the Properties Window change its ID to "ExtendedDateTextBox". 5. Add a few line breaks after the TextBox and add a new TextBox to your web page. In the Misc section of the Properties Window change its ID to "ExtendedRegExpTextBox". Configure the TextBoxSetting. 1. From the RadInputManager's smart tag, open the Property Builder dialog by clicking on the "Configure Input Manager" option. 2. Click the arrow in the Add Setting drop down in the bottom left corner of the dialog, choose "TextBoxSetting" and select the setting once it is added in the left hand-side pane. 3. In the Behavior section of the right-hand side pane set the BehaviorID property to "TextBoxSetting", the EmptyMessage property to "- Enter some text here -", and the SelectionOnFocus property to "SelectAll". 4. Check the check box in front of the "ExtendedTextBox" option in the middle pane of the dialog and click "OK" to add the setting to the managers settings. Configure the NumericTextBoxSetting. 1. From the RadInputManager's smart tag, open the Property Builder dialog by clicking on the "Configure Input Manager" option.
75
76
In addition to the methods listed above which are present in the client-side object for all the RadInputManager target controls, the TextBox controls targeted under DateInputSetting have the following additional methods: Method Return Type Description
77
[ASP .NET] Getting values on the client <telerik:RadCodeBlock ID="RadCodeBlock1" runat="server"> <script type="text/javascript"> function pageLoad() { var inputManager = $find("<%= RadInputManager1.ClientID %>"); var input = inputManager.get_targetInput("<%= TextBox1.ClientID %>"); input.set_value("Value Client Side"); } </script> </telerik:RadCodeBlock>
Validation
You can use ASP.NET validators for validating TextBox controls targeted in the RadInputManager settings. In this case validation works the same way as for regular TextBox controls. You simply have to set the ID of the TextBox control as the value of the ControlToValidate property of the validator.
78
3.9 Summary
In this chapter you took a tour of the "input" related RadControls and became familiar with how and where they are used. You saw some of the important properties,and notedwherethey all shared common properties. You created a simple application that used all four types of input control and made use of some of the common properties such as labels and empty messages. You learned to use the server-side API to respond to user input and to create input controls dynamically. You learned to perform common client-side tasks such as enabling and disabling some controls based on the responses to others, restricting input as the user types, and handling parsing errors. You also learned to use the input controls with other controls such as an ASP.NET validator or RadSpellCheck.
79
Client-Side API
4.1 Objectives
Learn the basic techniques for getting RadControls object references in client code. Use RadControl properties and methods. Learn the naming convention that will help you out in most RadControls client programming. Learn how to usethe JavaScript IntelliSense, providedout-of-the-box by RadControls for ASP.NET AJAX Q1 2010 and later. Learn how to use RadControl client events, the standard parameter list and naming convention. Learn how to attach and detach events on-the-fly. Build an application that displays a bread crumb trail as the mouse hovers a set of hierarchical tabs. This application incorporates knowledge on how to get object references, how to use client methods and events, and how to build and insert HTML on-the-fly.
4.2 Introduction
RadControls for ASP.NET AJAX brings a rich set of API objects, methods and events to client-side programming that let you achieve complicated tasks with maximum speed and flexibility. Its important to get familiar with client programming early on because every RadControl has a client API that can be used on its own or together with AJAX so that sever and client functionality work smoothly together. The client API is designed to be consistent between RadControls. Once you learn how to reference a RadControl, call client methods and respond to events, you're on your way to working with the rest of the controls the same way.
$find(): Provides a shortcut to the Sys.Application.findComponent() method, which returns the specified Component object. Expect to use this method every time you reference a RadControl on the client. This next example shows $find() being used in its simplest form: [JavaScript] Using $find() var menu = $find("RadMenu1"); In some cases, "RadMenu1" will be present, but $find("RadMenu1") will return null. A safer way to find your RadControl is to use a server tagtooutput the control ClientID to the $find() method. We leave it up to the RadControl to figure out the correct ClientID in case the control is nested withina master page or user controland the ClientID wouldn't be what we expect: [JavaScript] Using $find() with Server Tag var menu = $find("<%= RadMenu1.ClientID %>");
ID and ClientID
The ID propertyof a control identifies an ASP.NET server control. The ID is only unique within the current NamingContainer (page, user control,item template). The ClientID property is unique within the entire page. The ClientID will be rendered with the container control, an underscore and the control ID. If "RadMenu1" is located directly on the page the two
80
See the Telerik blog "The Difference between ID, ClientID and UniqueID" by Atanas Korchev for additional exploration of this topic.
$get(id, parentElement): This method is just for finding generic HTML elements, not RadControls.$get() Provides a shortcut to the getElementById() method. "parentElement" is the element to search but is optional. By default, the document is searched. [JavaScript] Using $get() var myDiv = $get("myDiv");
Fortunately, Visual Studio 2008 has some advanced client-side capabilities including JavaScript debugging, JavaScript IntelliSense and even CSS style intellisense. If you enter a <script> tag to your markup and press CtrlSpace, JavaScript IntelliSense is invoked and shows available properties and methods:
Gotcha! If you can't find any of the "$" functions, it's likely you don't have a ScriptManager or RadScriptManager on the page. The ScriptManager component brings in the MS AJAX library of functions. Just for fun, click the Ctrl key to temporarily hide the IntelliSense window so you can see the code below:
81
Once you begin typing, IntelliSense provides a hint window with the parameters for the current context (or press Ctrl-Shift-Space to invoke the window). You can see in the screenshot below that an ID is required.
Finish up by typing the server tag "<%= %>" and reference the RadControl ClientID:
Now you have a reference to your RadControl client object and can use its properties and methods. For more on the Microsoft AJAX Library, see the Client Reference (http://msdn.microsoft.com/enus/library/bb397536.aspx).
82
83
An important detail here is that the Telerik static client library (http://www.telerik.com/help/aspnetajax/telerik-static-client-library.html) exposes to<RadControlName>(object) and find<RadControlName>(id, parent) methods which gives you the ability to cast or find Telerik AJAX control's client object and then the IntelliSense will expose directly its properties, methods and events. Additionally, you will get information about the client methods signature and the type of the arguments passed to or returned from them.
84
85
Methods are lower camel-cased. That is, the first character is lower case and the following words making up the method name are title cased. For example focusNextItem(), hide(), findControl(). Properties are made up of getter and setter methods. The naming consists of the get/set, and underscore and lower-camel-cased property name. For example get_imageUrl(), set_ImageUrl(). Internal Methods are preceded with an underscore. These methods are notintended for public use. Legacy Methods and Properties may still be present and show upper-camel-casing, e.g. FocusNextItem(). Because these are legacy methods and properties, they are deprecated and you cannot count on these methods remaining usable.
To create a client event handler you enter a JavaScript function name to the "OnClient..." property and create a JavaScript function to match. The parameter list of a RadControl client function will always include "sender", i.e. the initiating object and "args". "Args" contains methods specific to the control and the event. The example below shows the OnClientItemClicked event handled by a "itemClicked()" function. In this case "sender" is the RadMenu client object and "args" contains a get_item() function. get_item() as you might have guessed returns the menu item that was clicked on. Using the item object returned from get_item() you can call the RadMenuItem client methods, i.e. get_text(), get_value(), get_level().
86
In the example, an alert dialog displays the value for the clicked menu item. The itemClicked() client event handler first checks that the item has a "level" of 1, i.e., is a child item, so that clicking the parent "Edit" item will not display the alert.
87
88
89
The the application first runs, there is no event handling for the menu. When the "Enabled Clicked Event" checkbox is clicked, checkItemClick() runs. If the check box is checked, then the add_itemClicked() method is called, passing the event handler name "itemClicked". Likewise, if un-checked, the menu's remove_itemClicked () method is called, passing the same "itemClicked" event handler name. The same pattern is used for the "Enable All Events" check box. You can find the project for this example at \VS Projects\Client API\Events. [ASP.NET] Adding and Removing Event Handlers <script type="text/javascript"> function itemClicked(sender, args) { // display the text for the clicked on item alert(args.get_item().get_text()); } function checkItemClick() { // get a reference to the menu var menu = $find("<%=RadMenu1.ClientID %>"); // get a reference to the checkbox var checkbox = $get("cbClicked"); if (checkbox.checked) { // add the event handler menu.add_itemClicked(itemClicked); } else { // remove the event handler menu.remove_itemClicked(itemClicked);
90
91
1. Create a new web application. Add a ScriptManager to the default page. 2. In the Solution Explorer, add a new folder and name it "Images". 3. From the Visual Studio 2008 installation directory, copy the image "DataContainer_MoveNextHS.png" to the project \Images directory. This image will contain the rightward pointing arrow that displays between each crumb. Images from Visual Studio 2008 can be found at \Microsoft Visual Studio 9.0\Common7 \VS2008ImageLibrary\1033\VS2008ImageLibrary\VS2008ImageLibrary\Actions\pngformat 4. Add a RadTabStrip to the default page. Set the Skin property to "Sunset", the OnClientMouseOut property to "MouseOut" and the OnClientMouseOver property to "MouseOver". We will code the two client event handlers later, after we set up the tab strip items. 5. Copy the ASP.NET markup below to inside your RadTabStrip tags. This step will populate the tab strip with multiple levels of tabs that can best demonstrate the bread crumbs in action. [ASP.NET] Defining the Tabs <Tabs> <telerik:RadTab runat="server" Text="Hot Drinks"> <Tabs> <telerik:RadTab runat="server" Text="Expresso"> </telerik:RadTab> <telerik:RadTab runat="server" Text="Mocha"> <Tabs> <telerik:RadTab runat="server" Text="With Chocolate Chips"> </telerik:RadTab> <telerik:RadTab runat="server" Text="White Chocolate"> </telerik:RadTab> </Tabs> </telerik:RadTab> </Tabs> </telerik:RadTab> <telerik:RadTab runat="server" Text="Cold Drinks" > <Tabs> <telerik:RadTab runat="server" Text="Frappuccino"> </telerik:RadTab> <telerik:RadTab runat="server" Text="Iced Coffee"> </telerik:RadTab> <telerik:RadTab runat="server" Text="Thai Ice Tea"> </telerik:RadTab> </Tabs>
92
93
94
JSON can be used as an easy-to-work-with alternative to XML. JSON can be de-serialized into objects and theobjects serialized back into strings. There are API's that can do these transformations on both the client and server. Webservices can return JSON automatically for immediate use within JavaScript.
JSON supports the usual basic typeflavors:numbers, strings, booleans, arrays, objects and null. The quickest way to understand how the JSON syntax works is to look at an example.Below is a sample JSON
95
Serializing JSON
96
97
4.11 Summary
In this chapter you learned the basic techniques used to obtain RadControl object references in client code and how to call methods and use properties of the client objects. You learned the consistent naming convention used throughout the RadControls client API so that you can re-apply that knowledge on new controls. You learned how to implement client side event handlers and how to add and remove event handlers on-the-fly. Finally, you built aweb page with a tabbed interface that displays a breadcrumb trail as the mouse hovered each tab.
98
5.1 Objectives
Examine how RadFormDecorator, RadToolTipManager, and RadToolTip can add polish to your user interface. Create a simple application to get confidence in using each of the controls. Become familiar withthe design time support for working with the user interface and information controls. This support includes Smart Tag, Properties Window, ToolTipTargetControl Collection Editor,and the RadToolTip design surface. Explore principal properties and groups of properties where 80% of the functionality is found. Learn to supply tool tip content in server-side code. Learn how to use the client-sideapi to work with tool tip properties and control when tool tips appear and disappear. Learn how to use RadToolTip to provide tool tips for the areas of an ASP.NET ImageMap.
5.2 Introduction
As you have seen with the RadControls we have examined so far, they all support skinning to give your Web site a consistent look and feel. This adds a level of polish to your application that is simple to achieve. The controls we will examine in this chapter let you extend that skin-based look and feel to standard ASP.NET elements such as buttons or tool tips.
RadFormDecorator
There are no RadControl analogs to the standard ASP.NET Button, CheckBox,RadioButton, or ScrollBarcontrols. However, when you want to add this functionality to your Web pages, this does not mean that you must go to great lengths in order to make them fit in with the skin you are using. There is a simple way to augment these controls by adding a skinning capability: the RadFormDecorator control. When you add RadFormDecorator to your page, you can configure it to apply a skin to any or all of the buttons, check boxes,radio buttons, or scroll barson the page.
RadToolTipManager
You can use RadToolTipManager to apply your preferred skin to all of the tool tips on your page. RadToolTipManager will automatically replace the standard ASP.NET tool tips with customized tool tips that can be as simple or elaborate as you want.
99
When using RadToolTipManager, you have complete control over the content and behavior of the tool tips on a page. You can add tool tips to any or all of the elements on the page.You can specify when, where, and how those tool tips appear and disappear, add animated effects, and even add your own custom content using an asynchronousserver-side callback.
RadToolTip
Where RadToolTipManagerassociates custom tool tips with multiple elements on the Web page, you can use RadToolTip to create acustomized tool tip for a single element. It shares most of the same properties as RadToolTipManager, so that you have the same level of control over when, where, and how the tool tip appears and disappears. An advantage to using RadToolTip is that you can add custom content using the Visual Studio designer, rather than in the code-behind.
100
When you are finished, your project should match the one supplied in \VS Projects\UI\GettingStarted.
101
5. On the Border page of the dialog, uncheck the Same for all box under border-style and set the right border style to "solid", set the border-width to "thin", and the border-color to "Olive". Then click OK to exit the dialog.
102
6. Select the cell immediately to the left of the one you just modified, and bring up its Modify Style dialog. In the dialog, set the font color to "Olive" and click OK. 7. If any additional columns appear to the right, select a cell in the column, right click, and select Delete|Delete Columns to get rid of them. 8. Select the left-most cell in the second row. Using the Properties Window, set its ColSpan attribute to 2. Then delete the cell to its right. 9. From the HTML section of the Tool Box, drag a Horizontal Rule into the cell. 10. Select the left-most cell in the third row, and bring up its Modify Style dialog. Set the Border attributes to match the cell in the upper left corner (a solid right border with "thin" border-width and olive bordercolor). 11. In the Properties Window for this cell, set the valign attribute to "top" and the Title attribute to "Check all the styles you want to see included in the listing." 12. Select the cell to the right of the cell you just changed, and using the Properties Window, set its valign attribute to "top" and its Title attribute to "Choose the media you want." 13. There should not be any more rows in the table, but if their are, delete them. 14. Back in the upper left cell, type the text "Music Styles". In the upper right cell, type "Media". 15. From the Standard Section of the Tool Box, drag a CheckBox control into the upper left cell of the table. Set its Text property to "Classical". 16. Add a line break after the check box, and then add another one with the Text property of "Classic Rock". 17. Add two more check boxes in the same fashion, and set their Text properties to "Jazz and Fusion" and
103
104
105
Smart Tag
The Smart Tag for each of the user interface and information controls is identical (except for the title). It contains only the common elements of RadControls Smart Tags: the Ajax Resources, Skin selection, and Learning center:
Properties Window
At design time, most of the work you do to configure these controls can be done using the Properties Window. As before, let us look at the most important properties of the controls.
RadFormDecorator
The most important property of RadFormDecorator is the Skin property. This property is the reason to use RadFormDecorator, as its entire function is to apply a skin to other ASP.NET controls on the page. You can set the Skin property using either the Smart Tag or the Properties Window. Two other properties let you specify which controls on the page are assigned the skin you select:
The DecoratedControls property lets you specify the types of controls that RadFormDecorator applies its skin to. By clicking the drop-down arrow in the Properties Window, you can get a list of control types and select the types you want:
106
Only controls of the selected types have the skin applied. The selections shown above result in the following markup: [ASP.NET] DecoratedControls <telerik:RadFormDecorator ID="RadFormDecorator1" Runat="server" DecoratedControls="Buttons, Scrollbars" />
The DecorationZoneID property lets you limit the scope of the RadFormDecorator to apply only to the children of a single element on the page. This is the client-side ID of an HTML element on the page. Only the children of that element are affected by the RadFormDecorator. Gotcha! Do not set DecorationZoneID to the ID of an element whose appearance you want to change. It must be set to the ID of a parent element.
If you do not specify the content using the properties of RadToolTip or RadToolTipManager, the tool tip displays the text it derives from the HTML element to which it is attached (called the "target" element). If the target element has a ToolTip attribute, that is used. If there is no ToolTip attribute, the Title attribute is used. You can override the text derived from the HTML element by assigning a value to the Text property of RadToolTip or RadToolTipManager. You can override the Text property by supplying custom content for the tool tip. On RadToolTip, this can be done using the design surface (described below), while on RadToolTipManager, you must use the server-side AjaxUpdate event (described in section on server-side programming).
You can add a title area to the tool tip by setting the Title property. You can specify whether the content area includes scroll bars by setting the ContentScrolling property.
107
If the AutoTooltipify property is true (the default), the tool tip manager automatically generates tool tips for any control that has a ToolTip or Title attribute. When attaching tool tips in this manner, you can limit the scope of the tool tip manager by setting the ToolTipZoneID property. ToolTipZoneID works the same
108
You can specify exactly which controls get tool tips by explicitly adding them to the TargetControls property collection.
This editor works like most collection editors, with Add and Remove buttons to add or remove items from the collection and a properties grid on the right to set the properties of the currently selected item. Each item in the collection has a TargetControlID property and an IsClientID property to let you specify the HTML element for which the tool tip manager should generate a tool tip. These properties work just like the properties on RadToolTip that have the same names.
The content area of that window is a design surface for providing custom content for the tool tip. You can add any HTML elements to this design surface, including ASP.NET controls. For example, the tool tip shown below has an IMAGE element and a RadioButtonList control:
109
When you add content to the design surface, it is automatically added to the RadToolTip control: [ASP.NET] Custom content on RadToolBar <telerik:RadToolTip ID="RadToolTip1" runat="server" > <asp:Image ID="Image1" runat="server" ImageUrl="~/Images/redbug.png" /> <asp:RadioButtonList ID="RadioButtonList1" runat="server"> <asp:ListItem Selected="True">Insects</asp:ListItem> <asp:ListItem>Arachnids</asp:ListItem> </asp:RadioButtonList> </telerik:RadToolTip> When you add custom content to a RadToolTip control, the content is displayed in the tool tip. In this case, the tool tip's Text property is ignored.
110
The complete source for this project is in \VS Projects\UI\ServerAjaxUpdate. [VB] Adding tool tip content in AjaxUpdate Protected Sub RadToolTipManager1_AjaxUpdate(ByVal sender As Object, ByVal e As Telerik.Web.UI.ToolTipUpdateEventArgs) Handles RadToolTipManager1.AjaxUpdate Dim text As String = "Click here to learn more." Dim graphic As New Image() graphic.ID = "imgExample" Select Case e.TargetControlID Case "btnInsects" graphic.ImageUrl = "~/Images/redbug.png" text = btnInsects.ToolTip Exit Select Case "btnBirds" graphic.ImageUrl = "~/Images/blackbird.png" text = btnBirds.ToolTip Exit Select Case "btnMammals" graphic.ImageUrl = "~/Images/hedgehog.png" text = btnMammals.ToolTip Exit Select Case "btnReptiles" graphic.ImageUrl = "~/Images/lizard.png" text = btnReptiles.ToolTip Exit Select Case "btnAmphibians" graphic.ImageUrl = "~/Images/frog.png" text = btnAmphibians.ToolTip Exit Select End Select e.UpdatePanel.ContentTemplateContainer.Controls.Add(graphic) e.UpdatePanel.ContentTemplateContainer.Controls.Add(New LiteralControl(text)) End Sub [C#] Adding tool tip content in AjaxUpdate protected void RadToolTipManager1_AjaxUpdate(object sender, ToolTipUpdateEventArgs e) { string text = "Click here to learn more."; Image graphic = new Image(); graphic.ID = "imgExample"; switch (e.TargetControlID) { case "btnInsects": graphic.ImageUrl = "~/Images/redbug.png"; text = btnInsects.ToolTip;
111
112
In this example, the tool tip does not appear automatically. Instead, it appears when the user clicks the assist button on the date input control. When that happens, the current time is assigned to the tool tip's Title property using the set_title() method, and the tool tip is displayed by calling its show() method. If the user closes the tool tip using the button it contains, the button calls the tool tip's get_title() method to read the current time, and assigns that value to the date input control. The button then calls the tool tip's hide () method to close the tool tip. [ASP.NET] Assisting data entry <script type="text/javascript"> function ShowToolTip(sender, args) { var toolTip = $find("<%= RadToolTip1.ClientID %>"); if (toolTip) { var now = new Date(); var time = now.getHours().toString() + ":"; var minutes = now.getMinutes(); if (minutes < 10) time = time + "0" + minutes; else time = time + minutes;
113
114
In the ASPX file, a <script> block declares the loggedIn flag, the OnClientBeforeShow and OnCLientBeforeHide event handlers, and a HideLoginToolTipfunctionthat hides the login tool tip. This last function will becalled from the script that the server-side button handler injects onto the page. Note that the content of the tool tip is contained in an UpdatePanel. This causes the "Log In" button to execute inside an asynchronous AJAX callback, so that the page does not need to reload when the user tries to log in. [ASP.NET] Client-side code and login tool tip declaration <script type="text/javascript"> var loggedIn = false; // OnClientBeforeHide keeps the login tool tip from closing // until the user is logged in function OnClientBeforeHide(sender, args) { if (!loggedIn) args.set_cancel(true); } // OnClientBeforeShow prevents the login tool tip from appearing // after a postback once the user has logged in function OnClientBeforeShow(sender, args) { if (loggedIn) args.set_cancel(true); } // HideLoginToolTip closes the login tool tip if it is showing function HideLoginToolTip() { var tooltip = $find("<%=RadToolTip1.ClientID%>"); if (tooltip) tooltip.hide(); } </script> <br /> This page cannot be used until you log in.<br /> <asp:Button ID="Button2" runat="server" Text="Post Back" /> <telerik:RadToolTip Skin="Office2007" Position="Center" Title="Enter Name ID="RadToolTip1" runat="server" TargetControlID="form1" RelativeTo="BrowserWindow" and Password"
115
116
117
118
5.8 Summary
In this chapter you looked at the user interface and information controls RadFormDecorator, RadToolTipManager, and RadToolTip. You created a simple application and saw how these controls can change the look-and-feel of standard ASP.NET controls and tool tips. You became familiar with the design-time support for using these controls and looked at the most important properties. You learned to use the server-side API to supply the content of customized tool tips. You learned to use the client-sideAPI to hide and show tool tips andwork with their properties so that they can perform functions on your Web pages. You also learned to add client-side ids to an image map so that it can be used with RadToolTip.
119
RadRotator
6.1 Objectives
Examine how RadRotator can display changing content on your Web page. Create a simple application to get confidence in using RadRotator. Become familiar withthe design time support for working with the rotator. This support includes Smart Tag, Properties Window,and the template design surface. Explore principal properties and groups of properties where 80% of the functionality is found. Learn to start and stop the rotator using the client-side api. Learn to use RadRotator when it is not bound to a data source. Coverflow mode Carousel mode
6.2 Introduction
RadRotator lets you display data from multiple records using a template. It can scroll through the records either vertically or horizontally, either as a continuous stream or as a slide show.
The rotator is highly configurable. The display of each frame is based on a template, so you can include any controls or HTML elements to make up the display. You can also configure the way the rotator cycles through its frames, and what actions cause the frames to cycle. Typically, the rotator is data bound to fetch records from a data source, although that is not strictly necessary. The items in the template are bound to fields from the data source.
120
When you are finished, your project should match the one supplied in \VS Projects\Rotator\GettingStarted.
3. Copy the following XML into the new file to create your XML data set and save the file: [XML] NurseryRhymes.XML <?xml version="1.0" encoding="utf-8" ?> <Rhymes>
121
122
123
Smart Tag
The RadRotator Smart Tag contains only the common elements of RadControls Smart Tags: the Ajax Resources, Skin selection, and Learning center:
Properties Window
At design time, most of the properties you will want to set to configure the rotator are available in the
124
AutomaticAdvance causes the frames to automatically scroll in a single direction. The ScrollDirection property specifies the direction ("Up", "Down", "Left", or "Right") that items scroll. The FrameDuration property specifies the time, in milliseconds, that the rotator remains still before scrolling to the next set of items. The ScrollDuration property specifies how long the rotator spends scrolling before stopping for the next FrameDuration. The WrapFrames property specifies whether scrolling starts over at the beginning when it reaches the last frame. The InitialItemIndex indicates the item to start on. The default value is 0 (the first item), but you can set it to a higher value to start on a later record. You can also set InitialItemIndex to -1 to start just before the first item. Buttons causes frames to scroll when theuser clicks onbuttons that appear outside the edges of the rotator. When RotatorType is "Buttons", the ScrollDirection property indicates both the scroll direction and where the buttons appear. In this case, it can be any or all of the four values, although including both horizontal and vertical scrolling can be a little confusing. To include more than one scroll direction, separate values using commas. (For example: "Up, Down".) As with AutomaticAdvance, you can set the ScrollDuration, WrapFrames, and InitialItemIndex properties, but the FrameDuration has no effect in this mode. ButtonsOver behaves just like "Buttons", except that scrolling occurs when the mouse moves over the buttons rather than when they are clicked. SlideShow is similar to "AutomaticAdvance", except that frames replace each other in a slide show fashion rather than scrolling in a specific direction. When RotatorType is "SlideShow", the FrameDuration property specifies the time before the current slide changes. Instead of the ScrollDirection and ScrollDuration properties, you can use the SlideShowAnimation property to set the transition effects. The WrapFrames and InitialItemIndex work the same way with slide shows as they do with scrolling modes. SlideShowButtons is to "SlideShow" what "Buttons" is to "AutomaticAdvance". That is, the rotator acquires buttons (based on the ScrollDirection property) which the user can click to change the current slide. FromCode leaves the rotator displaying the first frame (specified by InitialItemIndex) until you cause a change from a client-side script. We will look at this option more closely in the section on Client-Side Programming.
Managing Layout In addition to the ScrollDirection, four properties control the layout of the rotator and the frames it contains: Height, Width, ItemHeight, and ItemWidth. Height and Width are the dimensions of the rotator, while ItemHeight and ItemWidth give the dimensions of a single item. If you are trying to fit items neatly into the rotator, it is important to keep in mind that Height and Width give the dimensions of the entire rotator, including buttons, not just the viewing area.
Templatedesign surface
125 RadControls for ASP.NET AJAX
You can add any HTML elements, including ASP.NET controls,to this design surface and they become part of the template that is used to display records from the data source.To display data from the data source, add controls and bind the relevant property to a field from the data source. As with all templates, you can use the ASP.NET expression syntax (<% %>) to reference the data item when bindinga property of a control in your template. Typically, you use Container.DataItem inside the DataBinder.Eval() function, although when working with XmlDataSource, you can use a simple XPath() function call. For examples of using DataBinder.Eval() with Container.DataItem, revisit the Data Binding chapter. (You can also check out the Client-Side Programming example forthis chapter.)For an example of using XPath(), revisit the Getting Started section of this chapter.
When the page first loads, the rotator's RotatorType property is set to "FromCode", so that it does not move. When the "Play" button executes, it changes the RotatorType to "AutomaticAdvance" before calling startAutoPlay(). This is so that once the rotator is started, it keeps going. If the RotatorType were left as "FromCode", the startAutoPlay() method would merely advance the rotator a single frame, and then stop. [JavaScript] Play button's onclick handler function StartRotator() { var rotator = $find("<%= RadRotator1.ClientID %>"); // set rotatorType to automatic advance so that it keeps going // once started, and then start the rotator. rotator.set_rotatorType(Telerik.Web.UI.RotatorType.AutomaticAdvance); rotator.startAutoPlay(); // enable the pause, disable play var pauseButton = $get("btnPause"); var playButton = $get("btnPlay");
126
127
13. Navigate to the Images folder and select "fish1.png". 14. At this point, your RadRotator declaration should look like the following: [ASP.NET] RadRotator with first item <telerik:RadRotator ID="RadRotator1" runat="server" FrameDuration="1" Width="522px" ItemWidth="58px" Height="40px" ItemHeight="40px" ScrollDirection="Left"> <Items> <telerik:RadRotatorItem ID="item1" runat="server" > <ItemTemplate> <asp:Image ID="Image1" runat="server" ImageUrl="~/Images/fish1.png" /> </ItemTemplate> </telerik:RadRotatorItem> </Items> </telerik:RadRotator> 15. Copy the entire declaration for the first item, and paste it as a second item in the Items collection. Change the ID of the RadRotatorItem to "item2", and on the Image, change the ID to "Image2" and the ImageUrl to "~/Images/fish2.png". 16. Repeat this process until you have 10 items, giving each item a sequential ID ("item3", "item4", and so on), each image a sequential ID ("Image3", "Image4", and so on), and setting the ImageUrl to a randomly chosen image chosen from among the 5 images you added to the Images folder.
128
Starting from Q3 2010,Telerik RadRotator supports two additional RotatorTypes - CoverFlow and CoverFlowButtons. Both new modes can be set using RotatorType property of the control. You can enable CoverFlow mode of RadRotator by following the steps below: 1. Set the RotatorType property to CoverFlow. RadRotator's declaration <telerik:RadRotator RotatorType="CoverFlow" ID="RadRotator1" runat="server" Width="748px" ItemWidth="150" ScrollDirection="Left, Right" Height="233px" ItemHeight="113" ScrollDuration="500" FrameDuration="2000" PauseOnMouseOver="false" InitialItemIndex="4"> <ItemTemplate> <asp:Image ID="Image1" runat="server" ImageUrl='<%# Container.DataItem %>' AlternateText="<%# VirtualPathUtility.GetFileName(Container.DataItem.ToString()) %>" /> </ItemTemplate> </telerik:RadRotator> If the RotatorType="CoverFlowButtons" is set, then the items are moved by clicking the RadRotator's default navigation buttons located on the left and right side of the control. 2. You can use the following server code to populate the Rotator with Images: Populating images in RadRotator -C# string virtualPath = "~/ImagesSource"; //specify Images folder private void Page_Load(object sender, System.EventArgs e) { if (!IsPostBack)
129
130
131
Starting from Q2 2010,Telerik RadRotator supports two additional RotatorTypes - Carousel and CarouselButtons. Both new modes can be set using RotatorType property of the control. In order to enable Carousel mode of RadRotator follow the steps below: 1. Set the RotatorType property to Carousel: RadRotator's declaration <telerik:RadRotator RotatorType="CarouselButtons" ID="RadRotator1" runat="server" Width="810px" ItemWidth="280" Height="350px" ItemHeight="200" ScrollDuration="500" FrameDuration="2000" PauseOnMouseOver="false"> <ItemTemplate> <asp:Image ID="Image1" runat="server" ImageUrl='<%# Container.DataItem %>' AlternateText="<%# VirtualPathUtility.GetFileName(Container.DataItem.ToString()) %>" /> </ItemTemplate> </telerik:RadRotator> If the RotatorType="CarouselButtons" is set, then the items are moved by clicking the RadRotator's default navigation buttons located on the left and right side of the control. 2. You can use the following server code to populate the Rotator with Images: Populating images in RadRotator -C# string virtualPath = "~/ImagesSource"; //specify images folder protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { RadRotator1.DataSource = GetFilesInFolder(virtualPath);// Set datasource RadRotator1.DataBind(); } } protected List<string> GetFilesInFolder(string folderVirtualPath) { string physicalPathToFolder = Server.MapPath(folderVirtualPath);// Get the physical path string filterExpression = "*.gif"; string[] physicalPathsCollection = System.IO.Directory.GetFiles(physicalPathToFolder,
132
6.9 Summary
In this chapter you looked at the RadRotator control and saw some of the ways it can display a stream of changing content. You saw some of the important properties for configuring the rotator. You created a simple application displayed data taken from an XML file. You learned to start and stop the rotator using the clientside api. You also learned how to add items explicitly when the rotator is not bound to a data source.
133
Ajax
7.1 Objectives
Take a tour of the AJAX related controls including RadAjaxManager, RadAjaxPanel, RadAjaxManagerProxy and RadAjaxLoadingPanel. Build a simple AJAX-Enabled web application that first uses RadAjaxPanel, then substitutes RadAjaxManager. The application also displays a loading panel during the AJAX request. Explore the design time interface for each of the AJAX controls, taking special notice of where the controls are similar. You will learn how to access properties and methods through Smart Tag and Properties Window. Programmatically define AJAX settings at run-time on the server, detect which requests are triggered by AJAX and automatically run client-script after a response. Create custom AJAX requests to bridge client and server functionality and AJAX-enable controls that lack intrinsic AJAX abilities. Learn important client methods to toggle AJAX functionality, cancel requests and iterate AJAX settings. Also learn how to handle AJAX client events raised at request start and response end. Explore design decisions involved with AJAX enabling your application. Learn how to make Winforms-like user interfaces using AJAX-enabled user controls andhow the page lifecycle impacts working with AJAX-enabled user controls. See how the RadAjaxManagerProxy control provides visibility to RadAjaxManager settings in complex container-ship scenarios. Use RadScriptBlock and RadCodeBlock to handle common script + markup related issues.
7.2 Introduction
The RadAjax controls AJAX-enable your application with little programming or configuration effort on your part. The control set consists of RadAjaxPanel, RadAjaxManager, RadAjaxManagerProxyand RadAjaxLoadingPanel. RadAjaxPanel lets you instantly AJAX-enable an area of a web page simply by dropping controls on the panel. RadAjaxPanel mimics an ASP:UpdatePanel, i.e. any control on the panel that performs a postback automatically uses AJAX updates instead of a postback. The effect from the user's perspective is that only the panel area updates and the full page does not refresh. Use RadAjaxPanel when...
You want instant gratification. All controls dropped onto the panel are AJAX-enabled without further configuration. You want to start learning about how AJAX-enabled applications behave. The page has a simple layout with no complex interactions between controls. The controls are placed next to one another on the page.
That AJAX is involved does not guarantee a performant application. Keep in mind that whatever you put into the panel will be sent to the server on the AJAX update. If you put everything in the page into the panel, then the application can perform no better than a standard application. The trick is to cut down the amount of payload between client and server, to make discrete little updates that move the minimum amount of data. While RadAjaxPanel is an easy development experience, RadAjaxManager should be your go-to control when you need to AJAX-enable an application. It can do everything the RadAjaxPanel can and quite a bit more. Use RadAjaxManager when...
You have complex pages and where only small parts of the page need to be updated at any one time. You need fine tune control over the updates going to the server via AJAX.
134
You need to get every last drop of performance from all aspects of your application. Controls to be updated are placed in disparate locations on the page.
RadAjaxManagerProxy is a stand-in at design time when you need to configure RadAjaxManager from within UserControls or Content pages. RadAjaxManager can only be present once in a page, so the proxy is convenient in this situations. Later, when we use RadAjaxManager with a user control, it will be clear how RadAjaxManagerProxy makes the development experience easier. The RadAjaxLoadingPanel control is used to display a "spinny" graphic in the updating area while the update is performed to provide a little user feedback.
135
12. Now click the "Ajax Update" calendar. The label will change to display the new date and no other part of the page will change: no blinking of the page, no "spinny" in the tab and no loading progress bar.
136
6. Check "AjaxCalendar" in the first column and check "AjaxLabel" in the second column. Click OK to close the dialog.
137
7. Press Ctrl-F5 to run the application. The behavior is the same as the RadAjaxPanel version. The AJAX update performs very quickly with no screen flicker. While this is a trivial example, complex screens with updated controls in disparate locations can be handled just as easily.
RadAjaxLoadingPanel
The assignment of the label text is so quick the user is not going to notice any appreciable update time. In longer running operations, the user needs a little feedback.The RadAjaxLoadingPanel is a templated container associated with a RadAjaxManager. By default the loading panel has the text "Loading..." and an animated "spinny" image. 1. Add a RadAjaxLoadingPanel to the page. 2. In the RadAjaxManager Smart Tag, select Configure Ajax Manager. 3. In the second column (updated controls), select "AjaxLabel". In the third column (updated controls properties) select the loading panel from the LoadingPanelID property drop down list.
138
4. To simulate a long-running operation, lets add a "sleep" to the SelectionChanged event handler so you can see the loading panel. Add a call to System.Threading.Thread.Sleep() for 200 milliseconds: [VB] Simulate Long Running Operation Protected Sub AjaxCalendar_SelectionChanged(ByVal sender As Object, ByVal e As Telerik.Web.UI.Calendar.SelectedDatesEventArgs) System.Threading.Thread.Sleep(200) AjaxLabel.Text = AjaxCalendar.SelectedDate.ToShortDateString() End Sub [C#] Simulate Long Running Operation protected void AjaxCalendar_SelectionChanged( object sender, Telerik.Web.UI.Calendar.SelectedDatesEventArgs e) { System.Threading.Thread.Sleep(200); AjaxLabel.Text = AjaxCalendar.SelectedDate.ToShortDateString(); } 5. Re-run the application. When you click a date, the "spinny" graphic displays in the same location as the updated control. When the operation finishes, the graphic disappears and the updated control becomes visible again.
139
Enable AJAX is on by default, but you can disable this option to verify that your application works with standard post backs. In most cases your web page should work with standard post backs.A good debugging measure is to simply turn off AJAX and re-test your application without it.
Enable AJAX history is off by default, so the forward and back buttons on the browser are disabled. With
140
Enable update of Page <head> element if true allows updates to the page head element so that title and style sheet changes are applied. Choose LoadingPanelID for RadAjaxPanel lets you select a RadLoadingPanel from a list. On the RadAjaxManager Smart Tag the task is called Choose DefaultLoadingPanelID and lets you choose the loading panel that displays for all updated controls where not already defined.
The RadAjaxManagerProxySmart Tag has a single option that refers to the only task this control performs, Configure Ajax Manager. RadAjaxManagerProxy doesn't include any of the RadAjaxManager properties or methods except for the AjaxSettings property that is populated by this option.
The RadAjaxLoadingPanel Smart Tag options configure how the loading panel is positioned, the timing of when it displays and how it displays.
By default the loading panel displays in the same location as the updated control. If Is sticky is checked the loading panel displays where you have it positioned on the page at design-time. Initial delay time is the number of milliseconds before the loading panel displays. If the request completes before the initial delay time expires, the loading panel doesn't show. In the Getting Started example we had a loading panel with an artificial, "sleep()" inducedwait of 200 milliseconds. If you set Initial delay time to "1000", the loading panel never displays. Min display time is the minimum amount of time (in milliseconds) the loading panel displays even if the update operation completes sooner. This timing setting helps eliminate annoying flicker that can occur if the loading panel has just appeared and the request finishes.In theGetting Started example, if you set Min display time to "1000", the loading panel displays a full second, even though the request takes a little over 200 milliseconds. Imagine a "heads down" order entry system where a sales person is rapidly keying multiple order lines, one right after the other. Once the sales person enters a part number and a quantity, you might expect the system to lookup the sales price. If the system was running quickly, you wouldn't want to slow the sales person down with "spinny" animation for each entry, but ifthe database was under load and couldn't locate the product rightaway youwould want an indicator that processing was underway. In this case you could set the Initial delay time to a value that is over the average amount of time it takes to enter a line.
The loading panel doesn't actually replace the updated control but is displayed right over the top of it.Set a Transparency value of 0-100 so that the user can see the updated control underneath loading panel. 0 is opaque and 100 is completely transparent. The loading panel shown below is displaying over a label and
141
Properties Window
Most of the principal RadAjaxManager and RadAjaxPaneldesign-timeproperties have been touched on so far, but there are a couple of special purpose properties that you can reach at design-time only from the Properties Window:
RestoreOriginalRenderDelegate: If you have configured your applications to run in medium trust (http://msdn.microsoft.com/en-us/library/ms998341.aspx)you should set this property to false to avoid the error "InvalidOperationException: Not enough permissions...". RequestQueueSize: By design, the ASP.NET AJAX framework cancels the current AJAX request if you try to initiate a second request. Set RequestQueueSize greater than zero to automatically enable RadAjax queueing. You can test this behavior yourself using the Getting Started project.Add a Sleep() of 1000 milliseconds to the calendar SelectionChanged event handler and set the RequestQueueSize to "3". Run the application and click on three dates in a row quickly. Each will execute for a second and all will complete. Set the RequestQueueSize to "0" and you only see the last update. Queueing may makesense depending on the semantics of your application. For example if you had a list of tasks that could be executed and weren't dependent on one another, say, selecting a series of pre-defined emails to be sent, then queueing could be a good choice. If the application was an entry screen where the user could randomly work on different operations in the UI, then the user mightchange their mind at any timeand suddenly work on something else - here queueing might not be the way to go. The usability requirements determine the route to take. Requests exceeding RequestQueueSize are discarded.
Gotcha! "When I use RadAjaxManager, the AJAX-enabled controls are placed on a new line!". The reason for this behavior is that RadAjaxManager dynamically inserts MS AJAX UpdatePanel controls around the updated controls. The default render mode is Block. A new RadAjaxManager property UpdatePanelsRenderMode can be set to Inline so that the layout will not change. The screenshot below shows the effect of thedefault Block layout vs. the new Inline render mode:
142
The complete source for the project can be found in \VS Projects\Ajax\RenderMode. The project simply defines a button that updates a TextBox with the current time, and a check box that switches between the two render modes. The code to update the date is not strictly necessary to show the change in layout. [ASP.NET] Render Mode DemoMarkup
<asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <telerik:RadAjaxManager ID="RadAjaxManager1" runat="server"> <AjaxSettings> <telerik:AjaxSetting AjaxControlID="Button1"> <UpdatedControls> <telerik:AjaxUpdatedControl ControlID="TextBox1" /> </UpdatedControls> </telerik:AjaxSetting> </AjaxSettings> </telerik:RadAjaxManager> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" /> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack="True" Checked="True" OnCheckedChanged="CheckBox1_CheckedChanged" Text="Block" /> MISSING WIDGET TYPE: The "VB Colorized Example Code" Widget Type could not be found. The "VB Colorized Example Code" Widget Type may have been deleted since this Widget was created. MISSING WIDGET TYPE: The "C# Colorized Example Code" Widget Type could not be found. The "C# Colorized Example Code" Widget Type may have been deleted since this Widget was created.
143
144
Other Properties
RadAjaxManager and RadAjaxPanelhave a properties available at runtime only:
RadAjaxManager and RadAjaxPanelcan both indicate if they are in the middle of an AJAX request using the IsAjaxRequest property.For example, if you dropped this line of code into the Getting Started calendar SelectionChanged event handlers, one for the full postback and one for the AJAX-enabled version, the alert dialog would correctly reflect the state of each. [VB] Detecting AJAX Requests RadAjaxManager1.Alert(RadAjaxManager1.IsAjaxRequest.ToString()) [C#] Detecting AJAX Requests RadAjaxManager1.Alert(RadAjaxManager1.IsAjaxRequest.ToString()); The screenshot below shows the user clicking on the AJAX-enabled calendar and the alert shows that IsAjaxRequest is true:
145
You can define JavaScript that executes when a response returns to the browser by adding to the ResponseScripts collection: [VB] Adding a Response Script RadAjaxManager1.ResponseScripts.Add("alert('The date you selected was "_ + AjaxCalendar.SelectedDate.ToLongDateString() + "');") [C#] Adding a Response Script RadAjaxManager1.ResponseScripts.Add("alert('The date you selected was " + AjaxCalendar.SelectedDate.ToLongDateString() + "');");
146
147
The user clicks "Button1" and fires the onclick client event. "myFunction()" method runs in response to the client onclick event. This method gets a reference to the RadAjaxManager and fires the RadAjaxManager ajaxRequest() client API method. The OnAjaxRequest event fires on the server. The OnAjaxRequest event handler "RadAjaxManager1_AjaxRequest" runs in response to the event.
148
You can find the complete source for this project at: \VS Projects\AJAX\ClientAPI1 1. Create a new web application and add a ScriptManager component to the page.
149
If you look in the source view for the page, the markup should look something like the example below:
150
In the server OnAjaxRequest handler, first use theSystem.Random objectto get a number between 1..52. Add references to System.Web.UI.HtmlControls and System.Web.UI.WebControls in your "Imports" (VB) or "uses" (C#) section of code ifthey don't already existthere. Create an HtmlImage object. Construct the path for the playing card graphic and assign it to the HtmlImage src property. Make the ID property "card" (this is the identifier that the client code will expect to find) Set the "onclick" client event using the Attributes collection of the image object. Clear and add the HtmlImage to the Controls collection of cardDeckDiv. Create a Literal control andset its text to display the passed in argument and the new path. This literal also gets added to the cardDeckDiv Controls collection. The resulting code should look like the example below: [VB] Handling the Ajax Request Public Partial Class _Default Inherits System.Web.UI.Page Protected Sub RadAjaxManager1_AjaxRequest(ByVal sender As Object, ByVal e As
151
Events
RadAjaxPanel and RadAjaxManager both have two events. OnRequestStart fires just before the request is sent to the server. You can examine or alter the arguments sent to the requestor you cancancel the request altogether.When the page has been updated by the AJAX request the OnResponseEnd event fires.Used together, these two events can be used to log metrics on the performance of each request or to set and restore state. Some state related tasks you might perform are:
Setting the mouse cursor to a "wait" graphic, then back to its default. Disabling or hidingcertain controls during a request, then re-enabling or making visible afterward.
152
Displaying an animated control to indicate processing is taking place, then displaying an un-animated version of the control when the response returns. This also can typically be done using a RadLoadingPanel.
Both events have the same signature as other events in the client API: [JavaScript] OnRequestStart, OnResponseEnd Parameters function RequestStart(sender, args) { //.. } In this context "sender" is the RadAjaxManager object. Args has some significant methods to control the current event:
get_eventTargetElement(), set_eventTargetElement(): gets or sets the client object that raised the AJAX request. get_eventTarget(), set_eventTarget(): gets or sets the UniqueID of the element that raised the AJAX request. get_enableAjax(), set_enableAjax(): gets or sets if an AJAX request is to be performed at all. So, based on the initiating control or an updated control, you can actually determine if a particular request should instead become a standard postback. Note: You'll see how to get the list of updated controls from AjaxSettings in the upcoming Properties section of this chapter.
In this next sample we'll use both events to set the mouse cursor to reflect a busy state, and we will extend the ajaxRequest to pass multiple parameters.The sample uses the previous project as a basis, but adds the clicked card to a second div that contains five <span> tags. The effect is that the cards are "dealt" into a row.
You can find the complete source for this project at: \VS Projects\AJAX\ClientAPI2. 1. Start with the previous project (or a copy). 2. In the ASP.NET markup, just above "cardDeckDiv" add:
A hidden input field tab with id "Index" and value set to "1". Another div with id "discardPileDiv". Make sure it is marked with runat="server". You can modify the style attribute to suit your taste or copy it from the fragment below. Within the "discardPileDiv", add five <span> tags with id's "Span1" through "Span5?. The server code is expecting this specific naming convention. Again, make sure it is marked with runat="server".
153
154
Retrieve a reference to the "card" div element. From the card element, store the "src" property."src" contains the path of each card image. Retrieve the Index hidden field value. Populate a new "args" variable that contains the concatenation of the "src" and "Index"joined with a "&" delimiter."src" will contain the path to the clicked on image and "Index" will indicate the current span todisplay the next card in. Instead of passing a single argument to ajaxRequest()directly, you can pass multiple arguments joined by a delimiter as a single string.On the server call the String Split() method to convert the single string to an array for easier use.
Increment the Index value. You can use the JavaScript parseInt() function to explicitly convert the Index string value to a numeric. Pass "args" to the ajaxRequest() method. [JavaScript] Implementing the deal() function <script type="text/javascript" > function deal() { // get reference to the card div and extract source path var card = $get("card"); var src = card.src; // get the Index hidden field var Index = $get("Index"); // construct arguments to pass to server: // use "&" as delimiter. Pass the image path // and Index to current span. var args = src + "&" + Index.value.toString(); // increment the index between 1..5 if (Index.value >= 5) { Index.value = 1; } else { Index.value = parseInt(Index.value) + 1; } // get ajax manager and kick off ajax request passing arguments var ajaxManager = $find("<%=RadAjaxManager1.ClientID %>"); ajaxManager.ajaxRequest(args); } //. . . </script>
6. On the server, add the following namespaces to the "Imports" (VB) or "uses" (C#) section of the code: [VB] Adding Namespaces
155
GetSpan() locates and returns an HtmlGenericControl that represents one of the five <span> tags. AddCard() creates an HTMLImage control, sets the appropriate image path for the card number and adds the HTMLImage control to a given parent. [VB] Utility Methods ' retrieve reference to a given span Private Function GetSpan(ByVal index As Integer) As HtmlGenericControl Return TryCast(FindControl("Span" + index), HtmlGenericControl) End Function ' create a card image and add it to a parent container Private Function AddCard(ByVal parent As Control, ByVal CardPath As String) As HtmlImage Dim image As HtmlImage = Nothing If Not [String].IsNullOrEmpty(CardPath) Then image = New HtmlImage()
156
157
Use the String Split() method to convert the AjaxRequestEventArgs.Argument parameter into an array. From the array extract the card image path and the index of the current span to their own variables. Call the AddCard() utility method to add the latest card to the current span and also add the card path to the generic list. Create a new random card and display it in the "cardDeckDiv". [VB] Handling the OnAjaxRequest Event Protected Sub RadAjaxManager1_AjaxRequest(ByVal sender As Object, ByVal e As Telerik.Web.UI.AjaxRequestEventArgs) ' retrieve arguments sent from client and convert ' to array for easier processing Dim args As String() = e.Argument.Split("&"C) ' store the first argument parameter ' (the src property of the clicked-on card) Dim CardPath As String = args(0) ' store the span index where the next card image will be displayed Dim index As Integer = Integer.Parse(args(1)) ' create and add a card image to the current span: ' if the generic list of card image paths isn't populated ' yet, add to it, otherwise, re-use the list. AddCard(GetSpan(index), CardPath) If CardPaths.Count < 5 Then CardPaths.Add(CardPath) Else CardPaths(index - 1) = CardPath End If ' create the new card Dim nextCard As Integer = New Random().[Next](1, 52) Dim newCardPath As String = "Images/" + nextCard.ToString() + ".png" Dim newCardImage As HtmlImage = AddCard(cardDeckDiv, newCardPath) newCardImage.ID = "card" newCardImage.Src = newCardPath newCardImage.Attributes("onclick") = "deal()" End Sub [C#] Handling the OnAjaxRequest Event protected void RadAjaxManager1_AjaxRequest(object sender, Telerik.Web.UI.AjaxRequestEventArgs e) { // retrieve arguments sent from client and convert // to array for easier processing string[] args = e.Argument.Split('&');
158
159
Properties
The client API as usual lets you get and set important RadAjaxManager properties. For example, you can toggle if AJAX is enabled at all using get_enableAJAX()/ set_enableAJAX() methods. You can also get the complete list of AjaxSettings. The example below is added to theOnRequestStart client event handler from our previous project, but similar code could could be placed in any client event.
"sender" in this example is a reference to the RadAjaxManager object. Call get_ajaxSettings() to retrieve an array of objects that represents the Ajax Manager's current configuration. Iterate each of the settings and retrieve the initiating control id and yet another array of objects that represent updated controls. Iterate the UpdatedControls array and collect the control id for each. While iterating these arrays, append to strings that keep track of the initiating control and the updated controls for each initiating control. Display an alert thatdisplays thecollected information:
[ASP.NET] Retrieving AjaxSettings on the Client function RequestStart(sender, args) { var settings = sender.get_ajaxSettings(); var settingList = ''; for(setting in settings) { var initControlID = settings[setting].InitControlID; var updatedControls = settings[setting].UpdatedControls; var controlList = ''; for(control in updatedControls) { controlList += ' ' + updatedControls[control].ControlID; } settingList += '\nInitiated by: ' + initControlID +
160
161
162
[VB] Adding Controls in Page_Load Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Me.form1.Controls.Add(New TextBox()) End Sub [C#] Adding Controls in Page_Load protected void Page_Load(object sender, EventArgs e) { this.form1.Controls.Add(new TextBox()); } Just to recap the action so far:
Control properties are first set to their declared values from the markup. The page has only the single Button control with its declared defaults. Each control's TrackViewState() method is called during initialization. Each controls's LoadViewState() retrieves state information that was flagged "dirty" in the previous request. The retrieved state information is added back to the control's StateBags. StateBags are tracking view state at this point, so this state information is flagged "dirty" so that it will be available on the next request. This doesn't have much effect in our "dynamically added controls" scenario because we haven't added the TextBox yet. Page_Load fires. When the TextBox is added to the form Controls array, the control plays "catch up" and so has a chance to load its view state.
Be aware that even when an action on the page is AJAX-enabled, the entire page lifecycle still executes on the server, albeit with an smaller amount of view state information.
Assigning IDs
How does ASP.NET know what control to update with a given piece of the ViewState? The code above has an omission that happens to work out ok. In the example above ASP.NET automatically assigns the name "ctl02" to the TextBox. In the example below we explicitly assign a random ID to the TextBox for each page load and the result is that state is not retained. ASP.NETseesa different TextBox on each page load: [VB] Assigning a random ID Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Dim random As New Random() Dim textBox As New TextBox() textBox.ID = "myTextBox_" + random.[Next]().ToString()
163
Right-click the project Select Add | New Item from the context menu
164
Select Web User Control in the Add New Item dialog Click the Add button. Leave the default names for each: they should be named "WebUserControl1" and "WebUserControl2" to match the tab Value properties.
4. Navigate to the design view for WebUserControl1 and enter the text "Page 1", a standard ASP Button and a standard ASP TextBox. 5. Navigate to the design view for WebUserControl2 and enter the text "Page 2", a standard ASP Button and a standard ASP TextBox. 6. With the RadTabStrip selected in design view, click the Events button ( )Properties Window. Doubleclick the TabClick event to create an event handler. Do not enter any code for this event handler. It just needs to be present to trigger a postback but the logic will be housed in the page_load event. 7. In the Page_Load event handler, add the code below.
Each tab value has the path to the corresponding user control. The Page_Load event first uses that path to load the control. The same path is used as the control ID. The control is added to the web form's Controls collection. Note that using the path as an ID directly could backgire if your user control was in a different directory and contained problem "\" and "~" characters. We will address this issue later in this chapter. [VB] Loading the Selected Control Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Dim control As Control = Page.LoadControl(RadTabStrip1.SelectedTab.Value) control.ID = RadTabStrip1.SelectedTab.Value Me.form1.Controls.Add(control) End Sub [C#] Loading the Selected Control protected void Page_Load(object sender, EventArgs e) { Control control = Page.LoadControl(RadTabStrip1.SelectedTab.Value); control.ID = RadTabStrip1.SelectedTab.Value; this.form1.Controls.Add(control); }
8. Press Ctl-F5 to run the application. Notice that as you click the tabs, the corresponding user control displays, and that if you enter text and click the button, the text will also persist.
AJAX Enable
This next example simply AJAX-Enables the previous example.
165
3. Change the statement that added the dynamic control to the form's Controls array to use the PlaceHolder. [VB] Add to PlaceHolder Controls PlaceHolder1.Controls.Add(control) [C#] Add to PlaceHolder Controls PlaceHolder1.Controls.Add(control); 4. Press Ctl-F5 to run the application. The functionality should be the same as the previous application, except that now we have the benefits of AJAX performance and no postback flicker.
The interface will have a single method "FirstLoad()" with no parameters. Each web user control will implement this interface and the page that loads the control will call the
166
The method will not be fired when the postback is due to activity within the web user control.
[VB] Defining the IDynamicControl Interface Public Interface IDynamicControl Sub FirstLoad() End Interface 2. [C#] Defining the IDynamicControl Interface public interface IDynamicControl { void FirstLoad(); }
167
5. In the implementation for IDynamicControl, restore the previously saved TextInfo back to the TextBox: [C#] Restoring Saved Text On Control's First Load #region IDynamicControl Members Public Sub FirstLoad() Me.TextBox1.Text = Me.TextInfo End Sub #End Region [C#] Restoring Saved Text On Control's First Load #region IDynamicControl Members public void FirstLoad() { this.TextBox1.Text = this.TextInfo; } #endregion 6. Repeat the steps forthe"Modify the User Control" section on WebUserControl2. The steps are the same except when you define the "TextInfoKey" constant it should be named "TextInfoKey2" so that it is unique.
168
169
170
171
172
173
174
7.11 Summary
In this chapter we took a tour of the AJAX related RadControls, paying particular attention to the powerful and flexible RadAjaxManager. You built a simple AJAX-enabled application that first used RadAjaxPanel, then substituted RadAjaxManager to see how the two mechanisms contrast. You also leveraged RadAjaxLoadingPanel to provide better user feedback during AJAX requests. You learned how to define AJAX settings programmatically at run-time andat design-time using the RadAjaxManager Property Builder dialog to configure settings. Later you used RadAjaxManagerProxy to perform the same settings configuration within a user control. You built an application that "deals" cards to demonstrate how AJAX requests can be triggered on the client and handled on the server. You coded client-only functions to access common RadAjaxManager properties, e.g. configuration settings, enabling AJAX, canceling requests. You also handled RadAjaxManager client events that let you set and restore state at the beginning and conclusion of AJAX requests. We looked at design decisions regarding AJAX-enabling applications, took a walk through the ASP.NET page lifecycle and its impact on dynamically created user controls, and finally put this information to use in a Winform-likeUI demonstrating dynamic user controls together with AJAX. You saw how RadAjaxManagerProxy provides visibility to RadAjaxManager settings in complex container-ship scenarios. Finally, we looked at how RadScriptBlock and RadCodeBlock handle common script + markup related issues.
175
8.1 Objectives
Build the initial framework for a demonstration application that uses many of the RadControls for ASP.NET AJAXin concert. Setup the project structure. Learn how to setup and use ASP.NET Membership. Use RadFormDecorator and RadInput controls in an application.
8.2 Introduction
Learning to use individual RadControls for ASP.NET AJAXis the beginning, not the ending of this tutorial. Your use of RadControls will not be in button-and-a-label demos, but in real-world applications that employ multiple controls and technologies in concert including database access, complex user interfaces, user authentication, role assignment and personalization. This chapter introduces "ActiveSkill", a sample on-line exam application. A user of this application can maintain questions and create exams, as well as take an on-line exam and receive a test score.ActiveSkill has been scoped to be much smaller than a typical business application, but is large enough to involve issues you are likely to face in the trenches. The ActiveSkill is a MS SQL database that includes tables for Questions, Categories of questions and Exams. Stored procedures are included for most of the CRUD (Create, Read, Update Delete) operations so that the focus stays away from the database mechanics and stays on the use of RadControls for ASP.NET AJAX. ActiveSkill will also use ASP.NET Membership to handle user authentication tasks. This track of the tutorial will work gradually from simple login and registration pagesthat use some of the basic controls, to the Administrationsite that uses RadAjax + server code and finishing up at the user exam taking application that leans towards heavy use of the client API.The entire application will have a custom skin and will use a large portion of the RadControls for ASP.NET AJAX palette.
176
You can find the complete source for this project at: \VS Projects\ActiveSkill Getting Started\001
177
2. Enter "ActiveSkill" as the database name and leave the other settings at their defaults. Click OK to
178
2. In Microsoft SQL Server Management studio select the File menu, then Open | File. Locate theTSQL script file "\Database\CreateActiveSkillDatabase.sql" and and Click Open.
179
3. Press F5 to execute the script. This step will create all the tables and stored procedures required by the application. 4. In Microsoft SQL Server Management studio select the File menu, then Open | File. Locate theTSQL script file "\Database\PopulateActiveSkill.sql" and and Click Open. 5. Press F5 to execute the script. This step will populate the ActiveSkill tables with sample data. The database is now ready for the addition of ASP.NET Membership.
Allow users to create new accounts. The membership system includes behavior to automatically handle familiar situations like requiring the user to verify their email address before their account is activated. ActiveSkill will include an AJAX-enabledregistration page. Allow users to login to your web application. The membership system can be configured to automatically handle typical login issues: "number of failed attempts", password strength, error messages, etc. The login UI can be completely customized. The ActiveSkill login will include RadControls and will be skinned. Create and assign roles. For example, your application could have roles for "admin", "accounting", "browsers", etc., and allow people logged in with those roles to appropriate areas of your web site. ActiveSkill will have two roles, "admin" and "user". Work with the ASP.NET Membership API directly. Although the membership system has a lot of functionality that can be used right out of the box, we can also use the API along withthe controls to perform any of the membership methods. For example you could list all of the users on the system along with current login
180
2. Leave the Configure SQL Server for application services option selected. Click the Next button to display the Select the Server and Database page.
181
3. Enter the name of your MS SQL server and select the "ActiveSkill" database from the drop down list.Click the Next button to display a summary page. Click the Next button again to execute the creation of the ASP.NET Membership schema.
4. The completion page of the wizard indicates that the ASP.NET Membership database has been created. Click the Finish button.
182
Now the ActiveSkilldatabase will include the ASP.NET Membership tables and stored procedures:
183
184
7. Click the Create or Manage Roles link. Enter a new role name "Admin" and click the Add Role button. Enter another new role name "User" and click the Add Role button. Click the Back button. These roles are added to the membership database.
185
At this point, if you look at the membership database you will find an entry in the aspnet_Applications table for "/ActiveSkill" and two related records in aspnet_Roles for "Admin" and "User".
8. Create a new admin user: 1. On the Security tab click the Create User link. 2. Enter a new user account "Admin", set the Password and Confirm Password to "@password" (this will satisfy the password naming rules we have setup in the config file) and provide an email address. 3. Check the "Admin" role. 4. Click the Create User button. 5. Click the Continue button. 6. Click the Back button.
186
The new "Admin" user will now be in the membership database. 9. In Web.Config in the <system.web> tag, add authorizations for the "admin" and "user directories. This step allows members of the "Admin" role to access the \admin folder and the members of the "User" role to access the \user folder. [ASP.NET] Adding Access Authorizations <!--RadControls for ASP.NET AJAX Step By Step--> <location path="admin"> <system.web> <authorization> <allow roles="admin"/> <deny users="*"/> </authorization> </system.web> </location> <!--RadControls for ASP.NET AJAX Step By Step--> <location path="user"> <system.web> <authorization> <allow roles="user"/> <deny users="*"/> </authorization> </system.web> </location>
You can find the complete source for this project at: \VS Projects\ActiveSkill Getting Started\001\ActiveSkill
187
188
8. From the Login control Smart Tag, Login Tasks, select Convert to Template. 9. Select the top-most TextBox control next to "User Name". Notice that the ID property is "UserName". Delete the control. 10. Drag a RadTextBox from the ToolBox into the same spot occupied by UserName. Set the ID property to "UserName". Set the Skin property to "Black". The login control is expecting controls with ID's "UserName" and "Password", so the new RadControls we use to replace the existing controls must have those ID's. Forgetting this step generates the error "Login1: LayoutTemplate does not contain an IEditableTextControl with ID UserName for the username.". 11. Locate the TextBox "Password", just below "UserName" and delete it. 12. Drag a RadTextBox from the ToolBox into the same spot occupied by Password. Set the ID property to "Password". Set the Skin property to "Black". 13. Delete the "Remember me next time" check box. We will not implement this feature. 14. Right-click the table cell that holds the "Log In" button and select Insert | Rows Below from the context menu. Repeat this step to create a second empty row. 15. In the top empty table cell enter the literal text "Don't have an account?" 16. Drop a standard ASP Button control to the lower empty table cell. Set the ID to "RegisterButton" and the Text property to "Sign Up". The layout should look something like the screenshot below:
189
17. Select the Login control and in the Property Window Events ( ) button, double-click the LoggedIn event to create an event handler. Add the code below to the event handler. If the login is successful, the logged in user will be redirected to the admin or user page, depending on their role. [VB] Handling the Logged In Event Protected Sub Login1_LoggedIn(ByVal sender As Object, ByVal e As EventArgs) If Roles.IsUserInRole(UserNameTextBox.Text, "Admin") Then Response.Redirect("~\admin\AdminHome.aspx") End If If Roles.IsUserInRole(UserNameTextBox.Text, "User") Then Response.Redirect("~\user\UserHome.aspx") End If End Sub [C#] Handling the Logged In Event protected void Login1_LoggedIn(object sender, EventArgs e) { if (Roles.IsUserInRole(UserNameTextBox.Text, "Admin")) Response.Redirect("~\\admin\\AdminHome.aspx"); if (Roles.IsUserInRole(UserNameTextBox.Text, "User")) Response.Redirect("~\\user\\UserHome.aspx"); } 18. For the code above to work, you need to add System.Web.Security and Telerik.Web.UI to your "Imports" (VB) or "uses" (C#) section of code. [VB] Adding References Imports System.Web.Security Imports Telerik.Web.UI [C#] Adding References using System.Web.Security; using Telerik.Web.UI; 19. The LoggedIn event handler also references a UserNameTextBox property. Add the following property to the code-behind: [VB] Adding the UserNameTextBox Property
190
You can find the complete source for this project at: \VS Projects\ActiveSkill Getting Started\002\ActiveSkill
Configure custom fields in web.config. Add utility classes to encapsulate session, user and web profile personalization information. Working from the inner-most user control, outwards to the page, we will build the BillingControl first. Build the CreateUserWizard wrapper user control. This control will consume the BillingControl. Implement the Registration page, using the CreateUserWizard wrapper user to supply most of the
191
192
193
194
195
196
197
In the first cell of the "Title" row add a LoginName control from the ToolBox "Login" tab. Set the FormatString property of the LoginName to "Billing Info for {0}".
In the first cell of the "Share my results" row, add a standard ASP CheckBox control. Set the ID property to "cbShareMyResults". Set the Text property to "Share My Results". Put the cursor after the checkbox and hit Enter to create a hard break (<br />). Add a standard ASP Label control. Set the ID property to "lblShareMyResults". Set the Text property to "".
In the first cell of the "Credit Card Type" row add, a standard ASP RadioButtonList control. Set the ID property to "rblCardType". Using the Smart Tag select Edit Items. Add three items setting the Text to "Visa", "MasterCard" and "American Express" respectively. Set the Value properties to "1", "2" and "3". Set the first item ("Visa") Selected property to True.
Add a RadMaskedTextBox to the first cell of the row. Set the ID property to "tbCCNumber". Set the Label property to "Credit Card Number:", the Mask property to "####-####-####-####" and Skin to "Black". Add a standard ASP RequiredFieldValidator to the second cell. Set the ID property to "valreqCCNumber". Set the ControlToValidate property to "tbCCNumber", ErrorMessage to "A valid
198
Add a second standard ASP RegularExpressionValidator to the second cell. Set the ID property to "valregexCCNumber". Set the ControlToValidate to "tbCCNumber", theErrorMessage to "Enter a valid credit card number" and ValidationGroup to "BillingGroup".Set the ValidationExpression to "^((4\d{3}) |(5[1-5]\d{2})|(6011))-?\d{4}-?\d{4}-?\d{4}|3[4,7]\d{13}$ ". The regular expression above is a relatively simple sample that can be used for this demo. You should research for your own regular expression based on your security needs.
Add a RadTextBox to the first cell of the row. Set the ID to "tbCCName". Set the EmptyMessage property to "Enter Name:" the Label to "Credit Card Name:" and Skin to "Black". Add a standard ASP RequiredFieldValidator to the second cell. Set the ID property to "valreqCCName". Set the ControlToValidate property to "tbCCName", ErrorMessage to "Enter the name on the credit card" and ValidationGroup to "BillingGroup".
Add a RadNumericTextBox to the first cell of the row. Set the ID property to "tbExpMonth". Set the Label property to "Exp Month:", MaxValue to "12", MinValue to "1", ShowSpinButtons to True, and Skin to "Black". In the NumberFormat sub-properties set AllowRounding to False, DecimalDigits to "0". Add a second RadNumericTextBox to the first cell of the row. Set the ID property to "tbExpYear". Set the Label property to "Exp Year:", ShowSpinButtons to True, and Skin to "Black". In the NumberFormat sub-properties set AllowRounding to False, DecimalDigits to "0", GroupSeparator to "" and PositivePattern to "n".
10. In the last row add a standard ASP ValidationSummary. Set the VallidationGroup property to "BillingGroup".
199
200
Add a new user. Re-run the application and login as your new user. Notice the styled tool tips in the billing information page.
201
Once the user is created by the ASP.NET Membership system, this event fires. The method first retrieves the wizard's UserName property, uses the name to create a new ASUser object. The ASUser is assigned to the SessionManager User property. The user name is added to the "User" role. [VB] Handling the CreatedUser Event Protected Sub CreateUserWizard1_CreatedUser(ByVal sender As Object, ByVal e As EventArgs) Dim userName As String = (TryCast(sender, CreateUserWizard)).UserName SessionManager.User = New ASUser(userName) Roles.AddUserToRole(userName, "User") End Sub [C#] Handling the CreatedUser Event protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e) { string userName = (sender as CreateUserWizard).UserName; SessionManager.User = new ASUser(userName); Roles.AddUserToRole(userName, "User"); } 3. Create another event for the CreateUserWizard FinishButtonClick event. This step validates the "BillingGroup" set of validators and if the data is good, the UpdateUser() method is called to send the user entry on the billing control to the ASP.NET Membership database. [VB] Handling the FinishButtonClick Event Protected Sub CreateUserWizard1_FinishButtonClick(ByVal sender As Object, ByVal e As WizardNavigationEventArgs) Page.Validate("BillingGroup") e.Cancel = Not Page.IsValid If Page.IsValid Then
202
203
When the user clicks "Continue", the ASP.NET Member user is created, the user is added to the "User" role. The billing page of the wizard shows up prompting for the custom information using BillingControl. The user fills in the information and clicks the "Finish" button. The billing information is validated and the web profile is updated.
The "Complete" page of the wizard displays. When the user clicks "Continue" they are directed to the user home page.
204
To begin building the CreateUserWizardWrapper Control: 1. Right-click the \Controls folder and select Add | New Item and choose Web User Control. Name the control "CreateUserWizardWrapper.ascx". 2. Switch to the Design view of the control. From the Toolbox, Login tab drag a CreateUserWizard control and drop it on the design surface. Notice from the CreateUserWizard smart tag that the wizard is made up of "steps" where each step can be converted to a template. The Create user and Complete steps default to a template that can be altered using the "Customize Create User Step" and "Customize Complete Step" links. We will start by customizing the Create User Step to suit our purposes.
205
3. In the CreateUserWizard Smart Tag click the Customize Create User Step link. This will change will allow the page to be edited. 4. Change the default titling "Sign Up for Your New Account" to "Register". You can type this directly in the designer. 5. In the designer, move the mouse to the "Security Question" row of the table, just to the left of the row. The cursor should change to a rightward pointing arrow.
6. Right-click and select Delete | Delete Rows from the context menu. If you have any difficulty with this you can switch to the source view of the page and delete the row from there.
206
7. Replace the Label and TextBox controls for the "User Name", "Password", "Confirm Password" and "Email" with RadTextBox controls. 1. Be sure to set the RadTextBox ID'sto thevalues of the TextBox controls they are replacing, that is "UserName", "Password", "ConfirmPassword" and "Email". 2. Set the Label property of each RadTextBox to "User Name:", "Password:", "Confirm Password:" and "Email:", respectively. 3. Set theSkin of each control to "Black". 4. Set the Width of each control to "210px". 5. Set the TextMode property for both password controls to "Password". 8. Set the Align attributeto "Left"for the table cells containing "User Name:", "Password:", "Confirm Password:" and "Email. 9. From the CreateUserWizard Smart Tag select the Add/Remove Wizard Steps... link. This will display the WizardStep Collection Editor. 1. Select the "Sign up for Your New Account" step and set the ID to "CreateUserWizardStep1". 2. Select the "Complete" step and set the ID to "CompleteWizardStep1". 3. Click the Add button to add a wizard step to the list. Use the Up arrow button to position it before the "Complete" step. Set the Title to "Add Billing Information", AllowReturn to False and the ID to "BillingStep". 4. Click the OK button to close the WizardStep Collection Editor.
207
10. From the CreateUserWizard Smart Tag, drop down the "Step" list and select the new "Add Billing Information" step.
11. Drag BillingControl.ascx from the SolutionExplorer to the upper region of the CreateUserWizard.
208
12. Using the Smart Tag for the CreateUserWizard, drop the list of steps and select "Sign up for your new accounts". Gotcha! Make sure you set the step to the first page before you're done. When you run the page it will display the step that is set at design-time.
209
2. Add a reference to the Telerik.ActiveSkill.Common namespace. This will provide access to our utility classes WebProfile, ASUser and SessionManager. [VB] Adding References Imports Telerik.ActiveSkill.Common [C#] Adding References using Telerik.ActiveSkill.Common; 3. Using the Properties Window with the cbShareMyResults checkbox selected, click the events button ( ). Double-click the CheckChanged event. In the event handler, add the code below. If the "Share My Results" check box is checked, the ExamsVisible string constant is displayed, otherwise ExamsNotVisible is shown. [VB] Handling the CheckChanged Event Protected Sub cbShareMyResults_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs) lblShareMyResults.Text = IIf(cbShareMyResults.Checked,ExamsVisible,ExamsNotVisible) End Sub [C#] Handling the CheckChanged Event protected void cbShareMyResults_CheckedChanged(object sender, EventArgs e) { lblShareMyResults.Text = cbShareMyResults.Checked ? ExamsVisible : ExamsNotVisible; } 4. Using the Properties Window with the cbShareMyResults checkbox selected, click the events button ( ). Double-click the CheckChanged event. In the event handler, add the code below.If the "Credit Card Type" radio button list selection changes, the RadTextBox mask changes to reflect the correct number of digits.
210
211
212
213
In the first cell of the "Share my results" row, add a standard ASP CheckBox control. Set the ID property to "cbShareMyResults". Set the Text property to "Share My Results". Set the AutoPostBack property to True. Set the ToolTip property to "Check this box to share your results with others". Put the cursor after the checkbox and hit Enter to create a hard break (<br />). Add a standard ASP Label control. Set the ID property to "lblShareMyResults". Set the Text property to "".
In the first cell of the "Credit Card Type" row add, a standard ASP RadioButtonList control. Set the ID property to "rblCardType". Set the AutoPostBack property to True. Set the ToolTip property to "Choose a credit card type". Using the Smart Tag select Edit Items. Add three items setting the Text to "Visa", "MasterCard" and "American Express" respectively. Set the Value properties to "1", "2" and "3". Set the first item ("Visa") Selected property to True. Click OK to close the collection editor
Add a RadMaskedTextBox to the first cell of the row. Set the ID property to "tbCCNumber". Set the Label property to "Credit Card Number:", the Mask property to "####-####-####-####" and Skin to "Black". Set the ToolTip property to "Enter a valid credit card number". Add a standard ASP RequiredFieldValidator to the second cell. Set the ID property to "valreqCCNumber". Set the ControlToValidate property to "tbCCNumber", ErrorMessage to "A valid credit card number is required", Text to "*"and ValidationGroup to "BillingGroup". Add a second standard ASP RegularExpressionValidator to the second cell. Set the ID property to
214
Add a RadTextBox to the first cell of the row. Set the ID to "tbCCName". Set the EmptyMessage property to "Enter Name:" the Label to "Credit Card Name:" and Skin to "Black". Set the ToolTip property to "Enter the name on the credit card". Add a standard ASP RequiredFieldValidator to the second cell. Set the ID property to "valreqCCName". Set the ControlToValidate property to "tbCCName", ErrorMessage to "Enter the name on the credit card", Text to "*"and ValidationGroup to "BillingGroup".
Add a RadNumericTextBox to the first cell of the row. Set the ID property to "tbExpMonth". Set the Label property to "Exp Month:", MaxValue to "12", MinValue to "1", ShowSpinButtons to True, and Skin to "Black". In the NumberFormat sub-properties set AllowRounding to False, DecimalDigits to "0". Set the ToolTip property to "Select the credit card expiration month". Add a second RadNumericTextBox to the first cell of the row. Set the ID property to "tbExpYear". Set the Label property to "Exp Year:", ShowSpinButtons to True, and Skin to "Black". In the NumberFormat sub-properties set AllowRounding to False, DecimalDigits to "0", GroupSeparator to "" and PositivePattern to "n". Set the ToolTip property to "Select the credit card expiration month".
10. In the last row add a standard ASP ValidationSummary. Set the VallidationGroup property to "BillingGroup". 11. Configure AJAX for the page: 1. From the RadAjaxManagerProxy Smart Tag, click the Configure Ajax Manager link. 2. Check"cbShareMyResults" as an initiating control. Check "lblShareMyResults" as the updated control. 3. Check"rblCardType" as an initiating control. Check "tbCCNumber" as the updated control.
A CreditCardGroup class to contain profile information for groups custom fields defined in web.config. A WebProfile class to contain profile information relating to each logged-in user. That information includes the CreditCardGroup and other single fields defined in web.config (e.g. "ShareMyResults"). The ASUser class that contains the ASP.NET Membership object for the logged in user and the associated WebProfile. The SessionManager class used to make ASUser available anywhere in the application once the user has logged in.
215
216
217
218
219
220
221
222
223
8.15 Summary
In this chapter you built the initial framework for a demonstration application that uses many of the RadControls for ASP.NET AJAX. You setup the project structure, learned how to setup and use ASP.NET Membership and finally used RadFormDecorator and RadInput controls.
224
9.1 Objectives
Examine how the "real estate" management controls can help you manage the content areas of your Web pages. Create a simple application to get confidence in using the controls. Become familiar with the design time support for working with the "real estate" management controls. This support includes Smart Tag, Properties Window, and some collection editors. Explore principal properties and groups of properties where 80% of the functionality is found. Learn how to perform common server-side tasks on the RadDock control. Learn how to use the client-side api perform common tasks. Learn how to use these controls for more complicated tasks, such as creating dialogs and tool boxes or populating a portal page.
9.2 Introduction
The controls we will examine in this chapter are designed to help you manage the layout (or "real estate") of your Web pages. All of them define regions of the Web page where you can add the content you want to display. Some of these regions can move around the screen, others can be minimized or hidden away. By using these "real estate" controls, you can organize your Web pages and add flexibility that lets your users configure the layout in an individualized way.
RadWindow
RadWindow implements a pop-up window that displays content from an external source (another URL). You can use this control for a pop-up dialog or tool box, or simply as a secondary window for displaying additional content. Pop-up windows can be modal (disabling the rest of the page) or nonmodal (allowing the user to interact with the rest of the page while the pop-up is showing).
225
You have full control over what causes windows to appear, where they appear, and what size they start at. By specifying the icons that appear in the title bar, you can let users minimize, maximize, resize, move, pin, and close RadWindow controls with no coding on your part. If you don't want to allow users these capabilities, you can remove any or all of the controls from the title bar, or even hide the title bar entirely. Unlike ordinary browser pop-up windows, RadWindow objects are not suppressed by the Windows XP SP2 pop-up blocker mechanism. Also unlike browser windows, you can minimize RadWindow pop-ups into minimization zones that you add to the parent window.
RadWindowManager
If your Web application uses multiple pop-up Windows, you can organize them using RadWindowManager. By using RadWindowManager, your application also has access to "rad" versions of the alert, confirm, and prompt pop-ups, so that you can control the appearance of these useful dialogs instead of relying on the built-in browser versions. Unlike the built-in browser versions, which are limited to displaying simple text, you can even add HTML content to the "rad" pop-ups:
226
As with RadWindow, you can control the command icons that appear in the RadDock title bar. RadDock windows have built-in commands for pinning and unpinning, expanding and collapsing, or closing the window, plus the ability to add your own custom commands. You can hide the RadDock title bar, replacing it with a simple grip for dragging and dropping:
227
RadDock windows can be configured so that they must be docked, must be floating, or so that they can move freely between the two states. You can also limit individual RadDock windows so that they can only be docked in certain zones.
RadSplitter
RadSplitter also creates separate regions for displaying content to users. Unlike RadWindow and RadDock, however, the content regions that RadSplitter uses are not pop-up windows. Instead, they are resizable frames, called panes, that divide up a region of the Web page. The splitter can be configured to lay out its panes either horizontally or vertically. By adding split bars between the panes, you can enable the user to resize panes in the browser. Alternately, you can leave out the split bars, to create a static layout of separate panes on your Web page. In a splitter that contains split bars, individual panes can be "locked", so that they are not resizable along with the other panes of the splitter. Panes can display content from an external URL, like RadWindow, or content that is loaded with the Web page, like RadDock. The screenshot below shows a splitter that displays a radio button list that is loaded with the Web page in the left pane, and content from an external Web site in the right pane:
228
Panes that load their content with the Web page can hold any HTML elements, even another splitter. By nesting splitters with alternating horizontal and vertical orientations, you can create arbitrarily complex layouts.
RadSlidingZone
RadSlidingZone is a specialized control for optimizing layout that can only be placed directly inside the pane of a splitter. RadSlidingZone implements a set of tabs that can be used to slide out additional panes, called sliding panes, similar to the way Visual Studio lets you slide out panels such as the Properties Window or Solution Explorer. Like the sliding panels in Visual Studio, the sliding panes of a RadSlidingZone control can be docked in place by the user. By defining sliding panes in a sliding zone container, you can initially hide content that your users do not need to see all the time.
229
You can configure the orientation of the sliding zone and whether sliding panes expand when the user moves the mouse over their tabs or whether the user must click on a tab to expand it. Individual tabs can be configured to display text, an icon, or both. Sliding panes can be fixed in size, or resizable in the direction that they expand. You can also suppress the ability of the user to dock individual sliding panes.
RadDockZone and RadDock RadSplitter, RadPane, and RadSplitBar RadWindowManager and RadWindow
These controls will be used to generate the layout shown in the following screen shot:
230
We will look at RadSlidingZone and RadSlidingPane later, in the Control Specifics section. You can find the complete source for this project at: \VS Projects\RealEstate\GettingStarted
231
232
Set Animation to "Fade". Set Behaviors to "Resize, Minimize, Close, Maximize, Move, Reload". Set OpenerElementID to "LinkButton1". Set Title to "Telerik". Set VisibleStatusBar to false. Set NavigateUrl to "http://www.telerik.com". As before, be sure to include the entire URL.
6. Click the Add button again to add a second RadWindow to the collection. Set the following properties:
Set Animation to "FlyIn". Set Behaviors to "Resize, Minimize, Close, Maximize, Move, Reload".
233
Set OpenerElementID to "LinkButton2". Set Title to "Google". Set VisibleStatusBar to false. Set NavigateUrl to "http://www.google.com".
7. Click the Add button again to add a third RadWindow to the collection. Set the following properties:
Set Animation to "Resize". Set Behaviors to "Resize, Minimize, Close, Maximize, Move, Reload". Set OpenerElementID to "LinkButton3". Set Title to "Wikipedia". Set VisibleStatusBar to false. Set NavigateUrl to "http://www.wikipedia.org".
234
3. Experiment with the splitter by dragging on the split bar. 4. Click on the three link buttons to display the RadWindow controls. Note the different animation effects as they appear.
Smart Tag
The Smart Tag for each of the "real estate" management controls contains only the common elements of RadControls Smart Tags: the Ajax Resources, Skin selection, and Learning center:
235
The Skin property for these controls takes a bit of explanation. As you saw in the project you built in the Getting Started section, working with the "real estate" management controls involves nesting controls inside controls: you nested RadDock controls inside RadDockZone, RadWindow controls inside RadWindowManager, and RadPane and RadSplitBar controls inside RadSplitter. In all cases, the controls have a Skin property, even when (as in the case of RadWindowManager) they have no visual aspect on the Web page. For most of these controls, setting the Skin property of the parent control changes the default skin for all of its children. Thus, when you set the Skin property for RadWindowManager, the skin was inherited by all the child RadWindow controls, and when you set the Skin property for RadSplitter, the skin was inherited by the child RadPane and RadSplitBar controls. (This did not occur for RadDockZone and RadDock, but in the next section we will encounter another control, RadDockLayout, which does set the default skin for child RadDockZone and RadDock controls). Even if the skin is inherited from a parent control, an individual child control can override that default by setting its own Skin property.
Properties Window
At design time, most of the work you do to configure these controls can be done using the Properties Window. As before, let us look at the most important properties of the controls.
RadWindowManager
The most important property of RadWindowManager is the Windows property. This holds the set of child windows the manager controls. In the Properties Window, you can use the Windows property to bring up the RadWindow Collection Editor to add and configure each window in this collection. In addition to the RadWindow controls in the Windows property collection, you can use RadWindowManager to generate additional RadWindow controls from client-side code.
RadWindow
When RadWindow controls are added as children of RadWindowManager (using the Windows property collection), you can use either the Properties Window or the RadWindow Collection Editor to set their properties. If you add RadWindow controls to a page without using RadWindowManager, you can use the Properties Window to configure them. It is not necessary to use RadWindowManager with your RadWindow controls unless you want to use certain parts of the client-side api. It does, however, provide a convenient place to keep all of your RadWindow
236
RadDockZone
The most important property on RadDockZone is the Orientation property. It specifies how the dock zone lays out its docked controls.
When Orientation is "Vertical" (the default), docked controls are added one below the other in a single column. If this takes up more space than the value specified by its Height property, the dock zone acquires a scroll bar. If Height is not set, the dock zone expands to fit its docked controls. The FitDocks property specifies whether docked controls are resized when docked so that they fit exactly in the Width of the dock zone. When Orientation is "Horizontal", docked controls are added in rows. When a row is filled (the control would exceed the value of the dock zone's Width property, a new row is started. As with a vertical dock zone, the dock zone can sprout a scroll bar if the Height property is exceeded, or grow to fit if the Height property is not set. (The FitDocks property has no effect on a horizontal dock zone).
237
RadDock
RadDock controls can display any HTML content, including other ASP.NET controls. The simplest type of content you can specify is a string of text. To populate a RadDock control with text, simply set the Text property. To add more complex elements, you can't use the Properties Window; instead, use the Visual Studio designer to create a ContentTemplate. A simple example of this process was shown in the Getting Started project. You can also add content to a RadDock control in server-side code. An example of this is shown in the section on Server-Side Programming. You can use the Title property to specify the title that appears in the RadDock title bar. By default, this title bar is where the user clicks and drags to move the RadDock control around the Web page. If you want to hide the title bar, you can change the DockHandle property from "TitleBar" to "Grip", and the title bar is changed to a small grip area at the top of the control. (You can remove even that small grip area by changing the DockHandle property to "None", but then the user has no way to drag the control unless you provide it using client-side code). In addition to the title string, the title bar also displays a set of command buttons. There are three basic builtin command buttons: a Close button that is always present until the user clicks on it to hide the RadDock control, an Expand/Collapse button that lets the user minimize the dock window so that it hides its content or restore it so that it displays its content, and a Pin/Unpin button that appears when the dock window is not docked. You can use the DefaultCommands property to specify which of these built-in commands you want to have appear on the title bar. You can choose a single command, list two commands separated by a comma, or set DefaultCommands to "All" or "None". You can augment this list by adding your own custom commands using the Commands property. When adding custom commands, you can implement their behavior on the client-side by assigning a function to the OnClientCommand event handler, or you can implement them on the server-side by setting the AutoPostBack property of the command and supplying a handler for the server side Command event. When you set the Commands property, the DefaultCommands property is ignored, so be sure to add any built-in commands you want to the Commands collection as well. There are two properties that affect where the user can drag a RadDock control:
DockMode specifies whether the dock window must always be docked in one of the dock zones ("Docked"), whether it can never be docked but must always float ("Floating") or whether it can move freely between the two states ("Default"). ForbiddenZones is a comma-separated list of IDs for all the dock zones where the dock window cannot be docked. By using forbidden zones, you can arrange your Web page with different functional docking areas.
RadSplitter
The most important property on RadSplitter is Orientation. Orientation can be "Horizontal", in which case the splitter lays out its panes in a single column, or "Vertical", in which case the panes are laid out in a single row. That is, Orientation refers to the direction of the split bars between panes, rather than the direction in which panes are laid out. If the splitter contains split bars between panes, the split bars resize the Height of panes in a horizontal splitter, and the Width of panes in a vertical splitter. The ResizeMode property lets you configure how panes resize when the user drags on a split bar. ResizeMode can be "AdjacentPane", in which case only the panes adjacent to a split bar are resized when the bar is
238
RadPane
RadPane represents one of the panes laid out by a splitter. It can hold any HTML content that you add in the designer (including another splitter), or it can display external content (like RadWindow) if you set the ContentUrl property. When specifying the dimensions of a pane, you only need to specify the size in one direction, because the pane matches the size of the splitter in the other direction. Thus, in a horizontal splitter, you only set the Height of a pane, while in a vertical splitter, you only set its Width. Because users can resize the panes of a splitter, you can place limits on how much a pane can be resized by setting the MinHeight and MaxHeight or MinWidth and MaxWidth properties. You can prevent the splitter from resizing a pane by setting the Locked property to true. When a pane is resized so that it is too small to display all of its content, itcan either crop its display, or displayscroll bars. The Scrolling property lets you specify which option is used. Scrolling can by "None" (always crop), "X" (display horizontal scroll bars but crop vertically), "Y" (display vertical scroll bars but crop horizontally), or "Both" (display both vertical and horizontal scroll bars as necessary). In addition to resizing panes, split bars also include the ability to collapse and restore adjacent panes. You can use the Collapsed property of a pane to specify that it starts out in the collapsed state when the page first loads. RadPane has built-in ability to show a loading sign while a content page set through the ContentUrl property is being loaded in it. To turn on this functionality you should set ShowContentDuringLoad to false (the default value is true).
RadSplitBar
RadSplitBar has two important properties that determine how it can influence adjacent panes:
CollapseMode specifies whether the split bar has the ability to collapse and restore adjacent panes. It can be "None", "Forward" (it can only collapse and restore the next pane), "Backward" (it can only collapse and restore the previous pane),or "Both" (it can collapse and restore both the next and previous panes). When you set CollapseMode to let the split bar collapse and restore adjacent panes, it acquires one or two collapse buttons. When the adjacent pane is collapsed, the collapse button changes to a restore button. ResizeStep lets you configure the split bar so that it only resizes adjacent panes in fixed increments. ResizeStep is the size, in pixels, of one increment.
Collection Editors
All collection editors work essentially the same way, with an Add button to add items to the collection and a Remove button to remove the selected item,up and down arrow buttons to rearrange items, and a propertiespane to set theproperties of the currently selected item. You display the collection editor by clicking the ellipsis button in the Properties Window next to the property whose value is a collection. Some of the "real estate" management controls have collection properties that let you use a Collection Editor:
On RadWindowManager, the Windows property brings up the RadWindow Collection Editor where you can add and remove windows and set their properties. On RadDockZone, the Docks property brings up the RadDock Collection Editor, where you canedit the RadDock controls that appear docked in the zone when the page loads.
239
On RadDock, the Commands property brings up the DockCommand Collection Editor, where you can add custom commands.
We have already looked at the main properties of RadWindow and RadDock, but it is worthwhile, at this point, to look at the properties of the commands you can add using the DockCommand Collection Editor. When adding commands to the Commands collection, use the ClientTypeName property to specify the type of a command. Remember that when you set the value of Commands, the DefaultCommands property is ignored, so add in any built-in commands you want to include. You can use any of the following types:
Telerik.Web.UI.DockPinUnpinCommand: the built-in pin/unpin command. Telerik.Web.UI.DockExpandCollapseCommand: the built-in expand/collapse command. Telerik.Web.UI.DockCloseCommand: the built-in close command. Telerik.Web.UI.DockCommand: the default class for custom commands with one state (like the built-in close command). Telerik.Web.UI.DockToggleCommand: the default class for custom commands with two states (like the expand and collapse states of the built-in expand/collapse command).
For custom commands, you will want to set some other properties besides the ClientTypeName: If you want to implement the behavior of your custom command in server-side code, set the AutoPostBack property to true and provide a handler for the server-side Command event. The Command event handler is passed the value of the Name property in its arguments so that you can identify which command generated the postback if you have multiple custom commands. If you want to implement the behavior of your custom command in client-side code, leave the AutoPostBack property set to false and set the OnClientCommand property to the name of a client-side function that is called when the user clicks on the command icon. The Text property specifies the text of the tool tip that appears when the mouse hovers over the command icon and the CssClass lets you change the appearance of the button from the built-in icon supplied by the skin. When adding a custom toggle command, there are a few more properties you will probably want to set that are not available using the DockCommand Collection Editor. To set these properties, switch to the Source window,
240
You can find the complete source for this project at:
241
1. Create a new ASP.NET Web Application. 2. Drag a ScriptManager from the Tool Box onto the Web page. 3. Drag a Panel from the Standard section of the Tool Box onto the Web page. Set its Height property to "350px" and its Width property to "100px". 4. Give the Panel a border by setting the BorderStyle property to "Groove", the BorderWidth property to "5px" and the BorderColor property to "#9999FF". 5. Drag a RadWindowManager onto the Web Page below the Panel.
Set the Skin property to "Inox". Set the Behaviors property to "Resize, Minimize, Move". Set the OffsetElementID property to "Panel1". Set the VisibleOnPageLoad property to true. Set the MinimizeZoneID property to "Panel1". This sets the panel as the minimize zone for all the windows in the window manager's Windows property collection.
6. Click the ellipsis button next to the Windows property to bring up the RadWindow Collection Editor. 7. In the Collection editor, add four windows to the Windows property collection.
On the first window, set its Left property to "110px", Top property to "10px", Title property to "Telerik", and NavigateUrl property to "http://www.telerik.com". On the second window, set its Left property to "130px", Top property to "30px", Title property to "Google", and NavigateUrl property to "http://www.google.com". On the third window, set its Left property to "150px", Top property to "50px", Title property to "Yahoo", and NavigateUrl property to "http://www.yahoo.com". On the fourth window, set its Left property to "170px", Top property to "70px", Title property to "Wikipedia", and NavigateUrl property to "http://www.wikipedia.org".
8. Press Ctrl-F5 to run the application. When the application starts up, the four windows appear cascading to the right of the panel. You can move them around the Web page or resize them. When you click the minimize button in the title bar, they move to the minimize zone you created. When you restore the windows that are in the minimize zone, they return to their last position and size.
Sliding zones
Sliding zones comprise another desktop metaphor that you can bring to your Web applications: the sliding panels in applications like Visual Studio that hold content hidden away until it is needed. You can add Sliding zones to the panes of a splitter by placing a RadSlidingZone control into the content area of a RadPane control. RadSlidingZone is restricted so that it can only be placed inside a RadPane control. You can't use RadSlidingZone anywhere else. The RadSlidingZone acts as a parent to one or more RadSlidingPane controls. Each sliding pane implements a sliding panel that appears either in its "closed" state, as a tab in the sliding zone, or in an expanded state to display its content. Expanded sliding panes can optionally be made resizable, with a resize grip on the outer edge, and can be dockable, with a pin button in the title bar to let the user lock them in an expanded position. Before moving on to a walk-through that lets you create an application which includes a sliding zone, let's look at some of the important properties of these controls.
242
RadSlidingPane
The dimensions of a sliding pane (Height and Width properties) refer to its dimensions when it is in the expanded state. Because sliding panes are part of a splitter control, only one of the two properties is meaningful: the one that indicates how far from the tab the sliding pane expands. You cancontrol whether users are able to resize the sliding pane from the original width or height by setting the EnableResize property.When EnableResize is true, a resize grip appears on the outer edge to let the user resize the pane. For resizable sliding panes, the MinHeight and MaxHeight or MinWidthand MaxWidth propertieslet you place limits on how much the user can resize the sliding pane. The Title property lets you label the sliding pane. The tile appears in the title bar of the sliding pane, and, by default, labels the tab in the sliding zone when the sliding pane is hidden.In addition to the title, you can set the IconUrl property to supply an imagefor labelling the tab in the sliding zone. The TabView property controls whether the tab in the sliding zone shows the title, the icon, or both. The EnableDock property specifies whether the sliding pane can be "docked" (locked into place in its expanded state). When EnableDock is true, a pin icon appears in the title bar to let the user dock the sliding pane.While the sliding pane is docked, the parent RadPane of the slider is automatically resized so that the sliding pane no longer obscures any of the content of other panes.
243
You can find the complete source for this project at: \VS Projects\RealEstate\SlidingZones 1. Create a new ASP.NET Web Application. 2. Drag a ScriptManager from the Tool Box onto the Web page. 3. Using the Solution Explorer, add an Images folder to your project. Add the files "Calendar.gif" and "Colors.gif", which can be found in \VS Projects\Images, to the Images folder of your project. 4. Drag a RadSplitter from the Tool Box onto the Web page. Set its Height property to "300px", its Width property to "75%", and its Skin property to "Sunset". 5. Drag a RadPane control from the Tool Box onto the surface of the splitter. Set its Width property to "25px". 6. Before adding the sliding zone to the pane you just added, add a second RadPane control to the splitter below the first RadPane. In the content area of the second RadPane, type "This is the main pane of the splitter." Note that in this application, we are not using any split bars between the panes. 7. Drag a RadSlidingZone onto the first RadPane in the splitter (the one without any text). 8. Drag a RadSlidingPane from the Tool Box onto the RadSlidingZone.
Set its Width property to "226px". Set its Title property to "Calendar". Set its IconUrl property to "~\Images\Calendar.gif".
9. Drag a RadCalendar control from the Tool Box onto the RadSlidingPane and set its Skin property to "Sunset". 10. Add a second RadSlidingPane to the RadSlidingZone, beneath the first one.
Set its Title property to "Colors". Set its IconUrl property to "~\Images\colors.gif".
11. Drag a RadColorPicker control from the Tool Box onto the second RadSlidingPane and set its Skin property to "Sunset".
244
You can find the complete source for this project at: \VS Projects\RealEstate\ServerSide 1. Create a new ASP.NET Web Application and drag a ScriptManager from the Tool Box onto the Web page. 2. Drag a RadDockLayout control from the Tool Box onto your Web page and set its Skin property to "Sunset". We have not yet talked about the RadDockLayout control, and, as you saw in the Getting Started project, it is not always necessary to include one in a project that uses RadDockZone and RadDock controls. The purpose of the RadDockLayout control is to manage the state of the dock zones and dock windows. Without a RadDockLayout control, any changes that the user makes to the position or state of dock windows are lost as soon as the application performs a postback. RadDockLayout "remembers" the state of RadDock windows and restores it after a postback. Gotcha! RadDockLayout only "remembers" the state of RadDock and RadDockZone controls that are created inside it. If you add other RadDockZone and RadDock controls to your Web page outside the RadDockLayout, they will not retain their state after a postback.
245
246
8. Press Ctrl-F5 to run the application. Drag the RadDock controls off the dock zone, or rearrange them. Add some text to the text boxes. Then click the Postback button you added. Notice that not only do the RadDock controls retain their new positions, but the text in the text boxes is retained as well. To see why you use RadDockLayout, try removing that control from your application, running it again, and pressing the Postback button.
247
You can find the complete source for this project at: \VS Projects\RealEstate\ServerCommand This project adds "next page" and "previous page" custom commands to the RadDock controls from the codebehind. This is accomplished by a helper function called AddButtons: [VB] Populating the Commands collection Private Sub AddButtons(ByVal dock As RadDock) ' Create a command for the "Next" button Dim cmd As New DockCommand() ' Assign a name to identify it in event handlers cmd.Name = "cmdNextPage" ' Set AutoPostBack so it raises a Command event cmd.AutoPostBack = True ' Set CssClass to specify the appearance cmd.CssClass = "NextButton" ' Set Text to provide a tool tip cmd.Text = "Next page" ' Add the command to the Commands collection dock.Commands.Add(cmd) ' Repeat the process for the "Previous" button cmd = New DockCommand() cmd.AutoPostBack = True cmd.CssClass = "PrevButton" cmd.Name = "cmdPreviousPage" cmd.Text = "Previous page" dock.Commands.Add(cmd) End Sub [C#] Populating the Commands collection private void AddButtons(RadDock dock) { // Create a command for the "Next" button DockCommand cmd = new DockCommand(); // Assign a name to identify it in event handlers cmd.Name = "cmdNextPage"; // Set AutoPostBack so it raises a Command event
248
249
250
251
You can find the complete source for this project at: \VS Projects\RealEstate\ServerDockLayout
252
253
Provide the dock zones with information about the positioning of RadDock controls that they contain. This is done by setting the Positions and Indices properties of the event arguments.Both of these properties are indexed by the unique name of the RadDock control for each state. Positions holds the ID of the dock zone that contains the RadDock control, and Indices holds theindex of that control's position within thezone. Apply the properties to theRadDock controls.This is done by calling the RadDock.ApplyState method. If all the RadDock controls are contained inside dock zones, and none of the RadDock properties can change with the layout, you can omit this task. The current example performs this task because if a RadDock control is free-floating, its position must be restored.
[VB] Restoring the layout Protected Sub RadDockLayout1_LoadDockLayout(ByVal sender As Object, ByVal e As DockLayoutEventArgs) Handles RadDockLayout1.LoadDockLayout ' Check whether there is a cookie with a saved layout Dim dockState As HttpCookie = Page.Request.Cookies.[Get]("DockLayouts") If Not dockState Is Nothing Then ' get the serialized state list from the cookie Dim serializedList As String = dockState.Value If serializedList <> Nothing Then ' break the serialized list into individual strings Dim states As String() = serializedList.Split("|"c) Dim i As Integer = 0 While i < states.Length ' deserialize each state, and use it to assign ' the position and index of each state to the event arguments Dim state As DockState = Telerik.Web.UI.DockState.Deserialize(states(i)) e.Positions(state.UniqueName) = state.DockZoneID e.Indices(state.UniqueName) = state.Index ' apply the state to the RadDock control Dim dock As RadDock = DirectCast(FindControl(state.UniqueName), RadDock) If Not dock Is Nothing Then dock.ApplyState(state) End If System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1) End While End If End If End Sub [C#] Restoring the layout protected void RadDockLayout1_LoadDockLayout(object sender, DockLayoutEventArgs e) {
254
255
The client-side OnClientDockPositionChanged event occurs whenever the user stops a drag operation by dropping the RadDock control in a new position. The event handler checks the parent dock zone ID by calling the get_dockZoneID() method. If this is an empty string, the control was dropped in a floating position; otherwise, it was dropped on a dock zone. When the RadDock control is dropped in a floating position, the event handler "opens" the book by enlarging it. When the control is dropped on a dock zone, the book is "shelved" by resizing it to the dimensions of a book spine. [JavaScript] Resizing docked controls in OnClientDockPositionChanged function PositionChanged(dock) { // Check to zone ID to see if it landed in a dock zone if (dock.get_dockZoneID() == "") // if not, take it off the shelf TakeOffShelf(dock); else // if so, put it on the shelf PutOnShelf(dock); } // PutOnShelf sets the dimensions of a shelved book function PutOnShelf(dock) { dock.set_width(10); dock.set_height(48); } // TakeOffShelf sets the dimensions of an open book function TakeOffShelf(dock) { dock.set_width(150); dock.set_height(100); } You can find the complete source for this project at: \VS Projects\RealEstate\ClientSide
256
You can find the complete source for this project at: \VS Projects\RealEstate\ClientCommand The OnClientCommand handler uses the RadTextBox client-side methods to check the enabled state of the text box and change it. The handler is hooked up to the command object by setting the "OnClientCommand" property of the command object in the <Commands> collection of the RadDock control: [ASP.NET] Client-side commands <script type="text/javascript"> function ChangeEnable(dock, args) { // get the text box var edit = $find("<%= RadTextBox1.ClientID %>"); // toggle the enabled state of the text box if (edit.get_enabled()) edit.disable(); else edit.enable(); } </script> <telerik:RadDockZone ID="RadDockZone1" Runat="server" Height="150px" Width="300px" FitDocks="false"> </telerik:RadDockZone> <telerik:RadDock ID="RadDock1" Runat="server" Width="200px" Title="Details"> <ContentTemplate> <telerik:RadTextBox ID="RadTextBox1" Runat="server" EmptyMessage="(No Details)" TextMode="MultiLine" Height="100px" Width="194px" Rows="3" > </telerik:RadTextBox> </ContentTemplate> <Commands> <telerik:DockCommand Text="Toggle edit mode" OnClientCommand="ChangeEnable" /> </Commands> </telerik:RadDock>
257
In this example, the RadWindow control is visible when the page first loads, but does not have its NavigateUrl property set, so its content area is empty. In addition to the window, the page contains two buttons and two links (<a> elements). When the user clicks on the first button, the onclick handler assigns the content of the window using its setUrl () method. Before setting the URL, the onclick handler first checks whether the window is open, and if not, it sets the size and title of the window, calls the center() method to position it, and then uses the window's show () method to open it. If there is a RadWindowManager present on the Web page, you can also display a window by calling the radopen(URL, windowID) function. The links do not use the setUrl() method of the window. Instead, they simply set their target attribute to the ID of the window. Because RadWindow controls are automatically added to the frames collection of the browser, this works to assign the window as the target of the link, setting its content to the URL specified by the link's href attribute. The first link uses only the target and href attributes. If the window is open, the URL is displayed in the window. If not, the link does not work. The second link behaves like the first link, except that it also has on onclick handler that calls the window's show() method to display the window. Because of the onclick handler, this link always works. Finally, the second button calls the window's show() method to display the window if it is not showing. [ASP.NET] Manipulating RadWindow <script type="text/javascript"> function SetWindowUrl() { // get a reference to the window var window1 = $find("<%= RadWindow1.ClientID %>"); // check if it is closed
258
259
You can find the complete source for this project at: \VS Projects\RealEstate\ClientDialogs [ASP.NET] Using radprompt(), radconfirm(), and radalert() <script type="text/javascript"> var selectedValue = ""; // callback function for the confirm dialog function assignConfirmedValue(value) { // value is true if the user clicked OK if (value) { // get the date input and assign the supplied value var di = $find("<%= RadDateInput1.ClientID %>"); di.set_value(selectedValue); } else
260
261
262
When the user clicks on one of the two print buttons on the bottom of the page, the onclick handler obtains a referenceto the splitter and calls its getPaneById() method toget a reference to the pane that should be printed. When calling the pane's print() method, the onclick handler passes in an array of style sheets. Each element in the array is the path to a CSS file. (In this example, the array elements are simple file names because the CSS files are sitting in the project folder.) The first style sheet ("printStyles.css") changes the default properties of text on the page. The second style sheet ("Calendar.Office2007.css") is a copy of the Calendar style sheet for the Office2007 skin.If youclick the buttons to print the splitter panes, you will see that the style sheets are applied to the internal pane, turning the text blue, but not to the external pane, where the text remains its original color. We will look at style sheets for skins in the next chapter. For now, it is enough to understand that by including the "Calendar.Office2007.css" style sheet, the printed calendar can reflect the "Office2007" skin that was assigned to the RadCalendar control in the pane. You can find the "Calendar.Office2007.css" file in the "Skins\Office2007" folder inside the folder where you installed RadControls for ASPNET AJAX. [JavaScript] onclick handler to print panes function PrintPane(paneID) { // get a reference to the splitter
263
a <div> element that the pop-up tool window can influence. a <button> element to act as an opener element for the pop-up tool window. a RadWindow control to hold the color picker. The NavigateUrl property of the RadWindow control is set to a Web Form that contains the color picker.
In addition to these three elements, the main Web page includes a JavaScript function to assign a color to the <div> element. [JavaScript] Function to change the <div> color // SetPanelColor sets the background color of the // <div> element to the specified color function SetPanelColor(newColor) { var colorpanel = $get("ColorDiv"); colorpanel.style.backgroundColor = newColor; } The project also contains a Web Form that supplies the content of the pop-up on the main page. This Web Form
264
265
266
267
268
269
270
Not all of the changes listed above are required for all browsers, but by including them all, you can achieve the same effect regardless of the browser viewing your page. The full-page splitter shown above was generated using the following markup: [ASP.NET] Full-page splitter <html xmlns="http://www.w3.org/1999/xhtml" style="height:100%" > <head id="Head1" runat="server"> <title>Full Page Splitter</title> </head> <body style="height:100%;margin:0px" scroll="no"> <form id="form1" runat="server" style="height:100%;margin:0px"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <script type="text/javascript"> function ChangeUrl(sender, args) {
271
Because the splitter includes only a single pane, the pane fills up the entire space of the splitter. The splitter has its PanesBorderSize property set to 0 so that there is no border region to reveal its presence. Because there is no property to suppress the scroll bars of a RadDock control, you need to play a bit with the size of the splitter and the size of the RadDock control, until the splitter fits exactly in the RadDock client area. Thus, the only scroll bars that appear are the scroll bars of the RadPane inside the splitter, which appear as necessary
272
273
The most important thing to note about these controls is that the EnableViewState property of the RadDockZone control where dynamic docks are added is set to false. Because the contents of this dock zone change in the code-behind, the controls collection of the dock zone after a postback does not match the collection when the postback starts. This will lead to view state errors unless you disable the view state of the dock zone.
274
275
276
277
278
9.9 Summary
In this chapter youlooked at the "real estate" management controls, learning how they can help organize the content on your Web pagesinto flexible content areas that can be moved, resized, or hidden. You saw many of the important properties. You created a simple application that used dock zones and dock windows, a splitter, and some pop-up windows managed by a window manager. You also created simple applications to become familiar with minimize zones and sliding zones. You learned to use the server-side API with the RadDock family of controls, adding content in the code-behind, implementing custom commands, and preserving dock layout in a cookie. You learned to perform common client-side tasks such as responding to layout changes, implementing custom commands, manipulating windows, printing the panes of a splitter, and using the customizable alert, confirm, and prompt dialogs. Finally, you learned techniques that are important to some of the more common applications that use the "real estate" management controls, including implementing tool windows and modal dialogs, creating a desktop-like window by filling the entire Web page with a splitter, and creating dockable windows dynamically.
279
10.1 Objectives
Learnhow to use thebuilt-in skins to provide a consistent style to your controls and overall application Learn how skins use standard CSS files and how the styles interact with the rendered controls. Explore different techniques for registering and assigning skins. Alter an existing skin and create a custom skin.
10.2 Introduction
Skins let you style your entire application with a consistent look and feel. This example (screenshot below) shows the same application in multiple different skins. The code-behind and markup is completely identical between screenshots, so you can see that skinning truly separates appearancefrom functionality.
RadControls for ASP.NET AJAX use skins to control overall look-and-feel. A skin is a set of images and a CSS stylesheet that can be applied to control elements (items, images, etc.) to define their look and feel. To apply a skin to a RadControl, set its Skin property, either using the properties pane or the Smart Tag. Each control is installed with a number of preset skins that coordinate with the look of other RadControls using the same skin:
Black Default
280
Forest Hay Office2007 Outlook Simple Sitefinity Sunset Telerik Vista Web20 WebBlue Windows7
You can also alter existing skins or create your own skin from scratch. Set theSkin individually for each control in the designer, declaratively or in code. Or you can set theskin for the entireapplication in the web.config orusing code you can dynamically change the appearance of all controls in the application at runtime.
Add three tabs with Text "Default", "Telerik" and "Sunset". Make sure that the first tab "Default" has the Selected property set to True.
5. Add some standard ASP Button, RadioButton and CheckBox controls on the page. These will be skinned automatically by the RadFormDecorator.
281
6. Double-click the RadTabStrip to create a TabClick event handler. Change the event handler to use the code shown below. The code simply assigns the tab text, which happens to contain skin names, to the RadFormDecorator and RadTabStrip Skin properties. [VB] Handling the TabClick Event Protected Sub RadTabStrip1_TabClick(ByVal sender As Object, ByVal e As Telerik.Web.UI.RadTabStripEventArgs) RadFormDecorator1.Skin = e.Tab.Text RadTabStrip1.Skin = e.Tab.Text End Sub [C#] Handling the TabClick Event protected void RadTabStrip1_TabClick(object sender, Telerik.Web.UI.RadTabStripEventArgs e) { RadFormDecorator1.Skin = e.Tab.Text; RadTabStrip1.Skin = e.Tab.Text; } 7. Press Ctl-F5 to run the application. Try clicking the tabs to see how the three skins are applied.
282
Assigning Skins
As we saw earlier, you can assign the Skin property declaratively, in the designer or in code. If you want to register the skin globally, that is, declare that the entire application to use a particular embedded skin, you can add application settings to web.config. The example <appSettings> element adds a "Telerik.Skin" key with value "Hay". This sets all the RadControls for theapplication that uses this configuration to display the "Hay" skin. [ASP.NET] Adding Application Settings <appSettings> <!-- Sets the skin for all RadControls to Hay --> <add key="Telerik.Skin" value="Hay"/> </appSettings> If you want to create a custom skin, you can also set the EnableEmbeddedSkins property for every RadControl in the application at one time. The example below registers a custom skin for every RadControl in the application: [ASP.NET] Disable Embedded Skins and Add Custom Skin <appSettings> <add key="Telerik.Skin" value="MySkin" /> <add key="Telerik.EnableEmbeddedSkins" value="false" /> </appSettings> You can also mix-and-match settings so that one skin applies to all RadControls except a control that has a specific skin applied. The example below assigns the skin "Hay" globally except for RadMenu which is assigned
283
The settings applied at page level have top priority. The settings applied for a particular control in the web.config file are next in priority. The settings applied for all RadControls globally in the web.config file are last in priority.
284
Width="100%"
Add RadMenu markup to the markup for the page where indicated by the comment. The markup simply defines a few items and sub-items. [ASP.NET] The RadMenu Definition <telerik:RadMenu ID="RadMenu1" runat="server" Width="100%" > <Items> <telerik:RadMenuItem runat="server" Text="File"> <Items> <telerik:RadMenuItem runat="server" Text="Products">
285
Add RadPanelBar markup to the markup for the page where indicated by the comment. Again, this just sets up a couple levels of panel items so we can see how that looks when styled. [ASP.NET] The RadPanelBar Definition <telerik:RadPanelBar ID="RadPanelBar1" runat="server" Width="200px"> <CollapseAnimation Duration="100" Type="None" /> <Items> <telerik:RadPanelItem runat="server" Text="My Tools"> </telerik:RadPanelItem> <telerik:RadPanelItem runat="server" Text="My Searches"> <Items> <telerik:RadPanelItem runat="server" Text="Discontinued Products" ></telerik:RadPanelItem> <telerik:RadPanelItem runat="server" Text="New Products" ></telerik:RadPanelItem> <telerik:RadPanelItem runat="server" Text="On Order" ></telerik:RadPanelItem> <telerik:RadPanelItem runat="server" Text="Backorders" ></telerik:RadPanelItem> </Items> </telerik:RadPanelItem> <telerik:RadPanelItem runat="server" Text="Options"> </telerik:RadPanelItem> </Items> <ExpandAnimation Duration="100" Type="None" /> </telerik:RadPanelBar>
Add RadGrid markup to the markup for the page where indicated by the comment. We will add some minimal server code-behind todisplay a little data in the grid. [ASP.NET] The RadGrid Definition <telerik:RadGrid ID="RadGrid1" runat="server" GridLines="None" > <MasterTableView AutoGenerateColumns="true" ></MasterTableView> </telerik:RadGrid>
5. Handle the Page_Load event to get a list of skins. It is used as datasource for the RadGrid. RadGrid implements ISkinnableControl and so has a GetEmbeddedSkinNames() method. (More on RadGrid and databinding in later chapters). [VB] Handling the Page_Load Event Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not IsPostBack Then Dim skins As List(Of String) = RadGrid1.GetEmbeddedSkinNames()
286
You can find the complete source for this project at: \VS Projects\Skinning\AssigningSkins
287
When you need to change an existing skin, you can use various tools (to be discussed in a later chapter) to visualize the HTML and styles. From there you can discover specific styles that affect the aspects of appearance that you want to tweak.You canalso find more information in the online help about specific RadControl CSS skin file selectors.
Skin Files
The directory where RadControls for ASP.NET AJAX are installed contains a \Skins folder.Typically the structure will be: \Program Files\Telerik\RadControls for ASP.NET AJAX <version>\Skins Here's a snapshot of the \Skins directory:
288
Within the \Skins directory you will find a series of CSS files, one for each control, e.g. Editor.css, ColorPicker.css, etc. These are the base style sheets and govern the basic appearance and layout of the control that's not skin specific. For instance, a RadMenu has a certain general layout with menu elements having a particular relationship to one another that makes it look like a menu and not a combo box for instance. In the base style sheet you won't typically find colors and images. These are left to the skin specific style sheets. At the same level in the \Skins directory alongside the base style sheets you find a series of folders named after the skins they define. Inside one of these skin-named folders is another set of CSS files with naming convention <control name>.<skin name>.css.
289
The folders contain a set of images that are referenced by the the stylesheets:
The images and style sheets can be used as starting points for your own custom skins or as reference material when creating skins from scratch.
290
We can change one of the built-in skins to float the menu to the right and brighten up the top level font a few shades (see screenshot below).
The position of the menu is defined in the base style sheet, i.e. Menu.css and the color of the top level menu items is defined in Menu.Black.css. 1. Create a new web application, add a ScriptManager and a RadMenu to the page. Use the RadMenu Smart Tag to invoke the Build Rad Menu option. Add a few top level and child items to the menu. Set the Skin property to "Black". 2. Copy from the Telerik installation directory \Skins folder the file "menu.css" to the \Skins folder in your application. Within your application's \Skins folder, create a sub folder "\Black". Copy from the Telerik \Skins\Black folder to the \Black folder in your application both the file "Menu.Black.css" and the \Menu folder. Your project should now look something like the screenshot below:
291
3. In the designer, select the RadMenu and set EnableEmbeddedBaseStyles to False and EnableEmbeddedSkins to False. Now the RadMenu will display based off the CSS and images in your \Skins directory, not the embedded resources. Any changes you make to the CSS will now show up immediately in the control. 4. Open up "Menu.css" for editing. In the ".RadMenu" element change the "float" attribute to "right". The entire menu will not be right-justified on the web page. [CSS] Editing Menu.css .RadMenu { white-space:nowrap; float:right; position:relative; } 5. Open up \Black\Menu.Black.css for editing. Locate the CSS selector ".RadMenu_Black .rmLink". Change the "color" attribute to "#DfDfDf". This brightens up the un-selected top-level font. [CSS] Editing Menu .RadMenu_Black .rmLink { line-height: 32px; text-decoration: none; color: #DfDfDf; padding-left:3px; }
292
Press Ctl-H to find and replace. "Find What:" should be "_Black" For "Replace with:" enter "_MySkin". Click the Replace All button.
293
5. Set the Skin property of the RadMenu to "MySkin". 6. At this point you might expect to see your changes, but there's one last task. Drag "Menu.MySkin.css" to the page. This will register the new css file. It's very easy to forget this step...
294
10.7 Summary
In this chapter you learned how to use the built-in skins to provide a coherent,consistent style to your applications. You explored the general makeup of the skin CSS files and how the styles interact with the controls rendered in the browser. You learned multiple techniques for registering and assigning skins.You created your own custom skin starting with the "Black" skin as a basis.
295
11.1 Objectives
Introduce the bindableinterfaces and Data Source controls. Get a feel for declarative data binding by a RadToolBar to a SqlDataSource. Review the data binding related properties and learn how to bind to multiple data sources at one time. Learn how to bind RadControls in code, starting with binding simple arrays and lists, then binding hierarchical data, business objects and LINQ data. Learn how to handle data binding related server events.
11.2 Introduction
Any industry-strength web application relies on database data, for example MS SQL, Oracle or MySQL. RadControls can automatically bind to data stores using standard Microsoft supplied data source controls SqlDataSource, AccessDataSource, XmlDataSource, LinqDataSourceand ObjectDataSource or any DataSourceControl implementation. Once the control is bound you can use the data for display-onlyor configure the data sourceto support full CRUD (Create Read Update and Delete) operations. This chapter deals with some of the common ways you can work with data in your controls. Some of the more complex controls like RadChart, RadGrid and RadSchedulerhave additional properties, capabilities and UI helpers that will be explored within their own chapters. You can bind RadControls to a data source that implements one of the following interfaces:
IEnumerable: Supports simple iteration of a collection. ICollection: Extends IEnumerable and supports size, enumerator, and synchronization methods for collections. IList: Extends ICollection and is the base class for lists. IBindingList: Extends IList and supports binding to a data source. IListSource: Provides functionality to an object to return a list that can be bound to a data source.
Some of the implementations of these interfaces include generic lists, Arrays, ArrayLists, CollectionBase objects, and DataView/DataTable/DataSet objects. You can alsobind to business objects in multi-tier scenarios using ObjectDataSource, bind to XML using XMLDataSource and, for best flexibility and performance in .NET 3.0, LinqDataSource fits the bill nicely. You can bind most of the RadControls declaratively or at design-time and in server-side code. And of course you can couple AJAX requests with your server-side codefor better performance.Many RadControls, such asRadGrid and RadTreeView, also allow binding in client codewith data coming directly from a web service. It is best to use AJAX/server-codewhen some kind of process is involved and to use WebServices/client-code for data presentation. AJAX maintains the whole application state, providing integrity between the different components on the page, while Web services are pure, lightweight but have no sense of state. The properties used to bind each of the RadControls are very similar. Once you know how it works for one control, you can apply that knowledge against the rest of the controls. There are some variations on this rule:
Some of the more complex controls, particularly RadChart and RadGrid have additional properties used to map data to particular aspects of the specific control. Controls that are designed to display a hierarchy like RadTreeView and RadMenu have additional properties that define parent and child records forming the hierarchy. Controls such as RadComboBox or RadToolBar, are designed to work with flat data structures and have fewer properties as a result. Hierarchical controls also have a DataBindings that let you declaratively bind columnsof the database to
296
A connection string that defines the kind of database and its location. The connection string can be defined in the web.config file. For this walk-through we want to access standard Microsoft supplied "Northwind" data. The file Northwind.mdf and several otherexample databases are stored in the RadControlsinstallation directory under: \Telerik\RadControls for ASPNET AJAX<version>\Live Demos\App_Data
A Data Source control that refers to the connection string. The Data Source defines a specific query that defines the table and columns to be retrieved. Thiswalk-through willpulla product category name and ID from the Categories table in the Northwind database. The RadControl DataSourceID points to the ID of the Data Source on our web page and displays the data. RadChart, RadGrid and RadSchedulerare complex controls that have additional properties and UI helpers that will be discussed further within their own chapters
297
4. In the Data Source Configuration Wizard "Choose a Data Source Type" page, select the Database option. Click the OK button.
5. In the "Choose your Data Connection" page of the wizard click the New Connection... button. This step will display the Add Connection dialog.
298
In the Add Connection dialog, click the Change... button. This step will display the Change Data Source dialog.
In the Change Data Sourcedialog, select the "Microsoft SQL Server" data source type and click the OK button. This step will return you to the Add Connection dialog.
299
In the Add Connection dialog: Enter the Server name as ".\SQLEXPRESS". In the Connect to a database area of the dialog, click the Attach to a Database File option. Click the Browse button. Navigate to the directory where you installed RadControls for ASP.NET AJAX. Select the database file you want to use, e.g. "Northwind.mdb" and click the Open button to select the path. Click the Test Connection button to display a success alert if the settings are correctly entered. Click the OK button to close the Add Connection dialog.
300
7. At the "Choose Your Data Connection" page of the wizard, click the Next button.
301
8. In the "Save the Connection String to the Application Configuration File", leave the defaults and click the Next button.
302
9. In the "Configure the Select Statement" of the wizard: 1. Select the Specify columns form a table or view radio button option. 2. Select "Categories" from the drop down list of table names.
303
11. In the "Test Query" page of the wizard, click the Test Query button to see that thelist of category names and ID's are listed. Click the Finish button to automatically create the SQLDataSource control and assign it to theRadToolBar DataSourceID.
304
12. The design view of the page will look something like the example below. Notice that the SQLDataSource returns DataRowView objects and these are displayed because the RadToolBar doesn't know what columns should be used yet.
13. In the Properties Window, set the DataTextField property to "CategoryName". The design view doesn't show the actual data yet, but does show a series of "abc" to indicate the column will have string data. Note: The Skin property here is set to "Web20".
305
14. Press Ctl-F5 to run the application. The category names show up as RadToolBarButton instances, one button per category name.
Data Properties
RadControls that can be bound to Data Sources use these basic properties:
DataSourceID:If you are binding declaratively in ASP.NET markup (or setting the properties at design-time) you need to point DataSourceID at the ID of a Data Source control. DataSource:In complex or dynamic scenariosyou may need to assign theData Source at runtime. Instead ofsetting DataSourceID, leave that blank and assign the DataSource to the Data Source object (not the ID of theData Source).You must also call theDataBind() method of the control after setting DataSource. Gotcha! If you assign both DataSourceID at design-time and DataSource at runtime you get an error similar to "System.InvalidOperationException: Both DataSource and DataSourceID are defined on 'RadToolBar1'. Remove one definition." DataMember: If your Data Source is actually a DataSet object, how does the control know which table of the DataSet to bind to? DataMember specifies a table name of a DataSet. if DataMember is blank then the first table of the DataSet is used. DataTextField: You used this property in the last walk-through to bind a column to the Text property. The DataTextField column data is what the user will see in the user interface. DataValueField: This property is used to bind a column to the Value property of the control. You might typically use the DataValueField for ID columndata while the DataTextField displays what the user will see. DataNavigateUrlField: Some of the navigation controls include this field to contain a column name that holds a URL. When a navigation item is clicked on the browser automatically navigates to the associated URL.
DataTextFormatString: You can format the data automatically by defining a format string, e.g. "Category: {0}". Use the same formatting rules as used by the String.Format() method. The "0" column will represent the data found in the DataTextField column. AppendDataBoundItems: By default this property is false and data bound to the control will overwrite whatever data is already there. If AppendDataBoundItems is True, you can bind to multiple data sources or mix and match between items added at design-time and additional data introduced through binding. For example, you could add a tool bar button at design-time "My Button", then bind to "Categories" and finally
306
307
To hook this kind of data up to aRadControl you need to use the DataFieldID and DataFieldParentID properties. The DataTextField property is still used to display what the user actually sees in the browser. An additional property MaxBindDepth controls the number of levels that are included in the hierarchy. The default is "-1" and includes all levels of the hierarchy. This walk-through hooks this data up to a RadTreeView. You can find the complete source for this project at: \VS Projects\Databinding\DataBindings
308
4. Instead of selecting a table from the list, instead select Specify a custom SQL statement or stored procedure. This step will display the Define Custom Statements or Stored Procedure page of the wizard.
309
5. Enter the SQL below to the Select tab of the wizard page. The general purpose of the query is to pull ID, ParentID and Name columns from the "SelfReferencing" table. [T-SQL] Selecting from Table "SelfReferencing" SELECT ID, NAME, CASE WHEN ParentID = 0 THEN NULL ELSE ParentID end AS ParentID FROM SelfReferencing Gotcha! "This constraint cannot be enabled as not all values have corresponding parent values." This error may appear if a ParentID value doesn't point to an ID that exists in the table. The ParentID is allowed to be null though.If you look at the example data at the top of this lesson you'll see that the ParentID for "President" is "0". There is noID of "0" in the table. So how do you define the top level value? You can either change the table data to be null, or change the select statement to looklike theT-SQL above where a"case" statement checks if the value is"0" and changes it to null. The select statement in the "Define Custom Statements or Stored Procedures page of the wizard will look like the screenshot below.
310
On the "Test Query" page of the wizard, click the Test Query button and observe the results. The "President" will have a ParentID that is null and the ParentIDs for the other records will refer to IDs that exist in the table.
311
6. In the Properties window, set the DataFieldID property to "ID" and the DataFieldParentID property to "ParentID". 7. Press Ctl-F5 to run the application. The tree view control displays the self-referencing data as a hierarchy.
8. Stop the application and change the MaxBindDepth property to "3". Re-run the application to see that only the first three levels are displayed in the tree view.
312
In the markup below shows the <DataBindings> element containing several RadTreeNodeBinding elements. Each element defines the ImageUrl that's hard-coded to an image path within the project, a TextField that still points to the "Name" column in the database and a FormatString property that formats the TextField. There are three bindings defined with Depth set to 0..2.
313
314
Likewise, we can bind to a generic List<> of strings: [VB] Binding a Generic List Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not IsPostBack Then 'string[] movies = new string[] { "Inherit the Winform", "Gone With the Refresh", "Citizen Combo" }; 'RadComboBox1.DataSource = movies; 'RadComboBox1.DataBind(); ' Create and populate a generic list Dim movieMenu As New List(Of String)() movieMenu.Add("Show Times")
315
316
317
Again, if you assign the DataTextField the combo box is properly populated. You can change the example above to assign both DataTextField and DataValueField. Then set the AutoPostBack property to True and finally, create a SelectedIndexChanged event handler to display the text and value in the page title. [VB] Creating, Binding and Retrieving Bound Data Dim movieItems As New List(Of MovieMenuItem)() movieItems.Add(New MovieMenuItem("Show Times", 1)) movieItems.Add(New MovieMenuItem("Movies", 2)) movieItems.Add(New MovieMenuItem("Theaters", 3)) ' bind text and value to specific property names RadComboBox2.DataTextField = "Name" RadComboBox2.DataValueField = "ID" RadComboBox2.AutoPostBack = True RadComboBox2.DataSource = movieItems RadComboBox2.DataBind() '... Protected Sub RadComboBox2_SelectedIndexChanged(ByVal o As Object, ByVal e As RadComboBoxSelectedIndexChangedEventArgs) Me.Title = "Text: " + e.Text + " Value: " + e.Value End Sub [C#] Creating, Binding and Retrieving Bound Data List<MovieMenuItem> movieItems = new List<MovieMenuItem>(); movieItems.Add(new MovieMenuItem("Show Times", 1)); movieItems.Add(new MovieMenuItem("Movies", 2)); movieItems.Add(new MovieMenuItem("Theaters", 3)); // bind text and value to specific property names RadComboBox2.DataTextField = "Name"; RadComboBox2.DataValueField = "ID"; RadComboBox2.AutoPostBack = true; RadComboBox2.DataSource = movieItems; RadComboBox2.DataBind(); //... protected void RadComboBox2_SelectedIndexChanged(object o,
318
Server Events
Look for three three basic events in most data bound RadControls.
The OnDataBinding event fires first when the controls data binding expressions are about to be evaluated. OnItemDataBound fires when each item in a collection is bound to data. This event is control specific and has a different naming convention for some controls, i.e. RadTabStrip uses OnTabDataBound, RadTreeView uses OnNodeDataBound and tool bar has OnButtonDataBound. The general pattern for all of these OnFooDataBound events is that a custom set of event arguments are passed in to provide a reference. In the arguments is a property for the item being bound and inside the item object are the properties for the item (Text, Value, ToolTip, etc.) and a DataItem reference that lets you get at the underlying object being bound. When you bind to a SqlDataSource, the DataItem will be a DataRowView. If you bind a list of some custom object, then the DataItem will be that custom object type. This event gives you maximum flexibility to use the data against the item in whatever way you choose. ItemDataBound is used to populate properties that don't have directly binding support, e.g. ToolTip, Visible, Enabled, etc.
The OnDataBound event fires when the control is finished binding its data. Use this event to guarantee that all the control's data is present.
Here's a short example that populates the tool tip for each item in a RadComboBox. The combo is bound to a list of "Car" objects: a simple object that has three properties, Name, ID and Comment. You can find the complete source for this project at: \VS Projects\DataBinding\ServerSideEvents
319
Inside the ItemDataBound we get the RadComboBoxItemEventArgs passed to the event handler. Remember that this parameter will be slightly different for each RadControl but the pattern will be quite similar. Inside RadComboBoxItemEventArgs you can find the Item property (or Tab or Node or Button). And within Item is DataItem that represents the chunk of data we just bound to. In this case the type is "Car" so DataItem is cast to be a Car type so that the Comment property is accessible. You can also put a breakpoint on the first line of this handler and see the underlying type for DataItem. In the case of standard database data sources, its DataRowView.
In the ItemDataBound event the DataItem is retrieved and cast to type "Car", the Comment property is accessed and assigned to the Item's ToolTip property. [VB] Handling the ItemDataBound Event Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) ' Create a list of car objects Dim cars As New List(Of Car)() cars.Add(New Car("Lamborghini", 1, "Based in the small Italian village of SantAgata Bolognese, near Bologna")) cars.Add(New Car("Aston Martin", 1, "Headquarters are at Gaydon, England"))
320
321
We will create a Tasks object that contains a generic list of Tasks, can retrieve a list of tasks and can delete a task.The list of "Items" are stored in the Session In the "Items"accessor, if Session "Items" is null then a few sample items are created and fed into the list. Note: This use of the Session is merely a way to persist the data while keeping the size of the example down and avoiding data access issues not central to this topic. The Task object itself is relatively trivial and has two properties, one for Name and one for ID. [VB] Implementing Tasks and Task Objects Public Class Tasks ' Stores a list of Tasks in the Session. ' This simulates a kind of persistent storage Public ReadOnly Property Items() As List(Of Task) Get If HttpContext.Current.Session("Items") = Nothing Then Dim result As New List(Of Task)() result.Add(New Task("Sign up for seminar", 1)) result.Add(New Task("Write Linq blog", 2)) result.Add(New Task("Get latest RadControls download", 3)) HttpContext.Current.Session("Items") = result End If Return DirectCast(HttpContext.Current.Session("Items"), List(Of Task)) End Get End Property ' method used by the object data source Select Public Function GetMyData() As List(Of Task) Return Me.Items End Function ' method used by the object data source Delete Public Sub DeleteMyData(ByVal id As Integer) Dim foundTask As Task = Me.Items.Find() Me.Items.Remove(foundTask) End Sub Public Sub stuff(ByVal test As String) End Sub End Class #region Task object Public Class Task Public Sub New() End Sub Public Sub New(ByVal name As String, ByVal id As Integer) _id = id
322
323
324
After selecting the business object to consume and hitting the Next button, the "Define Data Methods" page displays. There are tabs to help define each of the supported CRUD operations, Select Update, Insert and Delete. The selections here populate ObjectDataSource properties SelectMethod, UpdateMethod, InsertMethod and DeleteMethod that contain just the name of the methods without the parenthesis. In this example we just want to select and delete. The Select tab has a list of methods supported by the business object. In this case, only "GetMyData()" returns any values, and so onlythat method shows up in the list. If you had another method"GetMyString()" that returned a stringfor example, it too would show up in the list.
325
On the Delete tab of the "Define Data Methods" page, you can choose a method that accepts a parameter. Notice that GetMyData() doesn't show up in this list because it does not take a parameter.
326
After clicking the Finish button to complete the ObjectDataSource definition the next question is, "how does the delete operation know what record to delete?". Each of the method properties is coupled with a parameters collection property.
327
Clicking the DeleteParameters ellipses displays the Parameter Collection Editor where you define parameters used by the method. In some cases you can define that the "Parameter source" as a control with a particular property, but the collection editor does not always make this visible so we can leave the parameter source set to "None" and supply the parameter value in code.
328
Some RadControls, like RadGrid can automatically trigger CRUD operations from a data source. You can also trigger data source methods directly in code. In this example we use the ItemClick event of a RadPanelBar. The DeleteParameters "id" member is supplied the clicked on value, then the ObjectDataSource Delete() method gets called. The Select method is called implicitly by virtue of being bound to the control. [VB] Handling the ItemClick Event Protected Sub RadPanelBar1_ItemClick(ByVal sender As Object, ByVal e As Telerik.Web.UI.RadPanelBarEventArgs) ' fill the delete parameter with the value for the clicked item ObjectDataSource1.DeleteParameters("id").DefaultValue = e.Item.Value ' delete the item in the data store and rebind ObjectDataSource1.Delete() End Sub [C#] Handling the ItemClick Event protected void RadPanelBar1_ItemClick(object sender, Telerik.Web.UI.RadPanelBarEventArgs e) { // fill the delete parameter with the value for the clicked item ObjectDataSource1.DeleteParameters["id"].DefaultValue = e.Item.Value; // delete the item in the data store and rebind ObjectDataSource1.Delete(); }
329
Using LinqDataSource
Our first walk-through will take place in the designer only. All the heavy lifting will be performed by Visual Studio and the RadControls. You can find the complete source for this project at: \VS Projects\Databinding\LinqDemo 1. In Visual Studio, create a new web application and add a ScriptManager to the default web page. 2. Open the Server Explorer (View | Server Explorer) 3. Create a connection to the Northwind database by right-clicking the Data Connections node of the tree and select Add Connection... from the context menu.
In the Add Connection dialog, click the Change... button. This step will display the Change Data Source dialog.
In the Change Data Sourcedialog, select the "Microsoft SQL Server" data source type and click the OK button. This step will return you to the Add Connection dialog.
330
In the Add Connection dialog: Enter the Server name as ".\SQLEXPRESS". In the Connect to a database area of the dialog, click the Attach to a Database File option. Click the Browse button. Navigate to the directory where you installed RadControls for ASP.NET AJAX. Select the database file you want to use, e.g. "Northwind.mdb" and click the Open button to select the path. Click the Test Connection button to display a success alert if the settings are correctly entered. Click the OK button to close the Add Connection dialog.
331
Gotcha! If you attempt to connect using the Server Explorerand get an error "Cannot open default database. Login failed": click the Advanced button on the Add Connection dialog. Set the User Instance property to True. This will redirect the connection to an instance of SQL Server running under the users account. 4. In the Solution Explorer, right-click the project and select Add | New Item... 5. Select the LINQ to SQL Classes template, name it Categories.dbml and click the Add button to close the dialog. This step has created a DataContext object, a type that can be consumed by a LinqDataSource.
332
6. Drop a LinqDataSource component from the ToolBox Data tab to the default web page. Configure the data source:
Using the LinqDataSource Smart Tag, click the Configure Data Source... option. In the "Choose a Context Object" page of the wizard, leave the default "CategoriesDataContext" and click the Next button.
333
In the "Configure Data Selection" page of the wizard, select the "CategoryID and "CategoryName" columns and click the Finish button to close the wizard.
334
7. Drop a RadComboBox on the page. From the Properties window, set the DataSourceID to point to the LinqDataSource, DataTextField property to "CategoryName" and DataValueField to "CategoryID". 8. Press Ctl-F5 to run the application.
The performance and ease of use here is very similar to other data source controls. As we will see in the chapter on RadGrid, the performance differences will really show inhigh-volume data traffic situations in the 1+ millionrecords neighborhood.
335
[VB] Assigning LINQ Expression Results Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) ' the raw data Dim LinqFeatures As String() = {"Lambda Expressions", "Expression Trees", "Predicates", "Projections", "Key extraction", "LINQ to SQL", _ "LINQ to XML"} ' LINQ expression proceses data and outputs IEnumerable Dim query As IEnumerable(Of String) = From s in LinqFeatures_ Where s.StartsWith("LINQ") Order By s _ Select s ' IEnumerable is assigned and bound RadTabStrip1.DataSource = query RadTabStrip1.DataBind() End Sub [C#] Assigning LINQ Expression Results protected void Page_Load(object sender, EventArgs e) { // the raw data string[] LinqFeatures = { "Lambda Expressions", "Expression Trees", "Predicates", "Projections", "Key extraction", "LINQ to SQL", "LINQ to XML" }; // LINQ expression proceses data and outputs IEnumerable IEnumerable<string> query = from s in LinqFeatures where s.StartsWith("LINQ") orderby s select s; // IEnumerable is assigned and bound RadTabStrip1.DataSource = query; RadTabStrip1.DataBind(); }
11.8 Summary
In this chapter we introduced the interfaces that RadControls can bind to and the task specific Data Source controls that can be used to bind declaratively. You built a simple declarative data binding example using RadToolBar with SqlDataSource. You learned in more detail how the data binding properties were used. You also learned how to bind to multiple data sources at one time. In server-side code you learned how to bind simple arrays and lists, hierarchical data, business objects and LINQ data. You also learned how to handle data binding related server events.
336
12.1 Objectives
Learn the purpose and uses for templates in RadControls. Build a simple data-bound application using templates and data bound to elements within the template. Explore the details of binding expressions, starting with public server methods output directly to the browser and working through Container, DataItem, Eval() and Bind() methods. Learn how templates are presented within the design environment: multiple templates for complex controls like RadGrid, items templates for controls with multiple records (like the navigation controls) and single view templates for controls like RadRotator and RadPageView. Learn how to create custom templates on-the-fly. Learn how to find controls within templates on both the server and client.
12.2 Introduction
Templates let you paint a completely unique layout within your RadControls. Any arbitrary HTML can be used to fill templates: standard ASP.NET controls, HTML elements and other RadControls can all be placed inside of templates. RadControls may have multiple templates, each defining a particular area of the control. For example, RadPanelBar has only an "Item" template representing each panel while RadGrid has templates for the "no records" message, the paging area and the master table view edit form. The screenshot below shows a RadComboBox in the designer with the template opened and a RadTextBox added to the template surface. The diagram also shows the resulting markup.
337
Anything within the template can be boundto data for display-only or editing. The RadTextBox within the RadComboBox is shown having the Text property bound to a "CategoryName" column in a database table:
338
339
340
Set the DataTextField property to "ProductName". The product name will show up in the title bar of each panel. Set the DataValueField property to "ID". Also set the RadPanelBar Width property to "300px". This will accept the width of the items that will populate it.
341
From theStandard tab of the Toolbox add an Image control. In the Properties window, set the CssClass property to "ImageStyle".
Using the ImageSmart Tag select Edit Databindings.... In the DataBindings dialog, leave "ImageUrl" selected in the Bindable properties list. On the right side of the dialog, leave the Field binding radio button selected. In the Bound to drop down list, select "Name" ("Name" contains the name of an image that will be used in a URL path). In the Format entry add "~\\images\\{0}". Click OK to close the dialog and create thebindings in markup.
342
The output for this bound field will be placed in the Image controls ImageUrl property and look something like the markup example below. In the section on "Binding Expressions" we will explore what these binding expressions, i.e. <%# %> mean: [ASP.NET] Bound ImageUrl Tag <asp:Image ID="Image1" runat="server" CssClass="ImageStyle" ImageUrl='<%# Eval("Name", "~\\images\\{0}") %>' /> Gotcha! The ASPimage path should be pre-pended with a tilde ("~") to indicate the path is relative to the project path. It will work without the tilde in Internet Explorer but fail to displayin FireFox.
Place your cursor just to the right of the Image control and press the Enter key four times. This will place break ("<BR />") tags that will separate the text box controls you will add next. Drop four RadTextBox controls below the image, each one below the other. The design surface should now look something like this:
343
Select the first RadTextBox and set the Label property to "Mfg:", the Skin to "Telerik" and ReadOnly to "true". Using the RadTextBox Smart Tag select Edit Databindings....Bind the Text property to the "Manufacturer" field. Leave the Format blank. Configure the next three RadTextBox controls with these same settings but change the labels and and fields to:
Label: "Price:", Field: "Price" Label: "Quantity:", Field: "Quantity" Label: "Dimensions:", Field: "Dimensions"
4. Press Ctrl-F5 to run the application. Notice that the standard ASP:Image control has been bound to the data for the RadPanelBar and that the style has floated the image to the right side. All of the RadTextBox Text properties have been bound to columns in the table. The completed markup right now if you look at it is filled with "<%# %> server tags with expressions like "Eval("Manufacturer").This next section on Binding Expressions explains what these expressions are and how they are used. [ASP.NET] The ItemTemplate Markup <ItemTemplate> <fieldset class="FramesetStyle"> <%-- bound elements go here--%> <asp:Image ID="Image1" runat="server" CssClass="ImageStyle" ImageUrl='<%# Eval("Name", "~\\images\\{0}") %>' /> <telerik:RadTextBox ID="RadTextBox1" Runat="server" Label="Mfg:" LabelCssClass="radLabelCss_Telerik" Skin="Telerik" ReadOnly="true" Text='<%# Eval("Manufacturer") %>' Width="125px"> </telerik:RadTextBox> <br /> <telerik:RadTextBox ID="RadTextBox2" Runat="server" Label="Price:" LabelCssClass="radLabelCss_Telerik" Skin="Telerik" ReadOnly="true" Text='<%# Eval("Price") %>' Width="125px"> </telerik:RadTextBox> <br /> <telerik:RadTextBox ID="RadTextBox3" Runat="server" Label="Quantity:" LabelCssClass="radLabelCss_Telerik" Skin="Telerik" ReadOnly="true"
344
If you ran this now, nothing would show in the browser. You need to call DataBind() on whatever context the
345
...and pressing F5 to let the application continue, the output of the method shows up as a literal in the browser:
346
347
A typical use for these two objects is to populate the Text or Value properties of a control. To use Container you cast it to its actual runtime type and then use the methods of the type. In this case Container is a RadPanelItem so we cast Container as a RadPanelitem to get access to Text, Value and DataItem properties. The general rule here is that when a control is not data bound (ie when using statically declared items), you use Container, while with data-bound controls, you generally use Container.DataItem. The example markup below shows that you can populate any of the control's properties using information from Container or DataItem. Text and ToolTip properties are populated here by casting Container.DataItem to a DataRowView and accessing the corresponding columns. [ASP.NET] Populating Properties From Container.DataItem <ItemTemplate> <telerik:RadTextBox ID="RadTextBox1" runat="server" Width="200px" Label="Manufacturer:" Skin="Hay" Text='<%# (Container.DataItem as System.Data.DataRowView)["Manufacturer"] %>' ToolTip='<%# (Container.DataItem as System.Data.DataRowView)["SalesRepresentative"] %>'> </telerik:RadTextBox> </ItemTemplate> The browser output for the bound RadTextBox looks like this screenshot where the Text is populated with the manufacturer name and the tool tip shows the sales representative name.
348
Eval has an optional format parameter that allows substitution of a single value, making it easy to combine data values with other text: [ASP.NET] Formatting with Eval() ToolTip='<%# Eval("SalesRepresentative", "The sales rep is {0}") %>'> While Eval() is used for read-only access to the data.Bind() is a similar method used in place of Eval() for twoway data binding. Use Bind() when you want to update the data for controls containing values used as DataSource parameters. [ASP.NET] Using Bind() Text='<%# Bind("ProductName") %>'
349
After clicking the Edit Templates option, the designer for the control switches to "template editing mode" where an area is reserved for dropping controls. Also notice that the Smart Tag now has an End Template Editing option.
While RadComboBox has a single template type "Item Template", other RadControlsmay have multiple template types. When in template editing mode the SmartTag"Display" drop down listlets you navigate to different template typesfor editing. RadGrid for example lists templates for portions of the master table view.
350
You can select individual templates or select one of the bolded items in the list to edit a collection of templates all at one time. Selecting the bold "MasterTableView" from the list shows all the templates under it in the list:
As you can see there is a fair amount of variation between how individual RadControls present templates. The commonality between them is that the Smart Tag displays an Edit Templates link when templates are available for editing, provides a list of templates that can be edited and finally theEnd Template Editing link ends editing. The key is to look for the cues on the Smart Tag. For example, the RadToolBar doesn't show template related options until you have added buttons to the list. When you enter into edit template mode, the list of templates includes a template per button or split-button
351
RadControls that handle a single item such as RadRotator and RadPageView have no such "Edit Templates" Smart Tag options to begin with. Insteadthey are always in "template mode" as this screenshot of RadRotator shows:
352
353
354
Set the DataTextField property to "Name". Set the DataValueField property to "ID". Set the Orientation property to "VerticalLeft".
3. In the code-behind for the MyTemplate class, descend the class from ITemplate. 4. Right-click ITemplate and choose Implement Interface | Implement Interface from the context menu.
355
The class should look something like the example below: [VB] Implementing the ITemplate Interface Public Class MyTemplate Implements ITemplate #region ITemplate Members Public Sub InstantiateIn(ByVal container As Control) Throw New NotImplementedException() End Sub #End Region End Class [C#] Implementing the ITemplate Interface public class MyTemplate: ITemplate { #region ITemplate Members public void InstantiateIn(Control container) { throw new NotImplementedException(); } #endregion } 5. Implement the InstantiateIn() method. This method creates a standard ASP Image control, hooks up the DataBinding event so we can extract the path name for the image and adds the image to the container's Controls collection. In this case the container is a RadTab. The code also scales the image down slightly to fit on the tab and adds a right margin to position the image. A standard ASP Label control is also created and added to the containers Controls collection. Notice that
356
357
358
359
12.8 Summary
In this chapter you learned how templates are used within RadControls. First you built a simple application that used templates and data bound to elements within the template. We explored the details of binding expressions, starting with public server methods and working through Container, DataItem, Eval() and Bind() methods. You learned how to find controls in both server and client code.
360
13.1 Objectives
Build the Admin home page structure and the code-behind necessary to dynamically load user controls. Create user controls to be loaded into the Admin home page. Create a new ActiveSkill skin based on the existing "Black" skin.
13.2 Introduction
If you remember in the "Getting Started" chapter we created the beginnings of an "Admin" page. In another chapter on RadAjax we talked about how to dynamically load user controls on-the-fly. In the skinningchapter we created a custom skin. In this chapter we combine all of these techniques to fill out the functionality of the Admin home page so that it has:
Atab strip that users can use to navigate between user controls Aseries of user controls for each database function required. Anew custom "ActiveSkill" skin that will be applied to the entire application.
361
362
<img style="margin-left: 10px;" src="../Images/logo.png" /> </div> 7. To the top RadPane with ID "MainLeft", add a sliding zone, pane and tab strip. [ASP.NET] Adding the Tab Strip and Sliding Zone <telerik:RadPane ID="MainLeft" runat="server" Locked="True" Index="0" > <%--sliding zone, pane and rad tabstrip go here--%> <telerik:RadSlidingZone ID="MasterSlidingZone" runat="server" DockedPaneId="MasterSlidingPane" Height="100%" Width="15px"> <telerik:RadSlidingPane ID="MasterSlidingPane" runat="server" EnableDock="true" DockText="Tools" Title="Admin Tools" Height="100%" Scrolling="none" TabView="TextOnly" Width="160px"> <telerik:RadTabStrip ID="tsMain" runat="server" Orientation="VerticalRight" SelectedIndex="0" Height="336px" Width="160px"> </telerik:RadTabStrip> </telerik:RadSlidingPane> </telerik:RadSlidingZone> </telerik:RadPane> 8. To the bottom RadPane with ID "MainRight", add a <div> tag with id "divContent" and a standard PlaceHolder control. The PlaceHolder will be used to host user controls that will be loaded dynamically. [ASP.NET] Add Content Div and Placeholder
363
Text "Categories", Value "Categories.ascx", ImageUrl "~/images/Categories.png". Text "Questions", Value "Questions.ascx", ImageUrl "~/images/Questions.png". Text "Create Exams", Value "CreateExams.ascx", ImageUrl "~/images/Exams.png". Text "Schedule Exams", Value "ScheduleExams.ascx", ImageUrl "~/images/Schedule.png".
10. Use the RadAjaxManager Smart Tag to select the Configure Ajax Manager option. Set the RadTabStrip "tsMain" to update itself and the PlaceHolder1 control.
364
365
[VB] Load the User Control Private Function LoadUserControl(ByVal parentControl As Control, ByVal newControlPath As String, ByVal isFirstLoad As Boolean) As Control ' Load the control and set its id Dim control As Control = Page.LoadControl(newControlPath) control.ID = newControlPath ' the viewstate control will be out of sync with ' the previously loaded control. Temporarily shut off ' viewstate if this is the first load of the control If isFirstLoad Then control.EnableViewState = False End If ' add to the parent controls collection parentControl.Controls.Add(control) ' if this is the first load (first time the page is loaded or ' a new tab has been clicked) enable the viewstate again. Forgetting to ' reenable the viewstate will controls to be loaded only once. Then ' call the FirstLoad() method of the web user control for first time ' loading tasks. If isFirstLoad Then control.EnableViewState = True (TryCast(control, IASControl)).FirstLoad(Nothing) End If Return control End Function [C#] Load the User Control private Control LoadUserControl(Control parentControl, string newControlPath, bool isFirstLoad) { // Load the control and set its id Control control = Page.LoadControl(newControlPath); control.ID = newControlPath; // the viewstate control will be out of sync with // the previously loaded control. Temporarily shut off // viewstate if this is the first load of the control if (isFirstLoad) { control.EnableViewState = false; } // add to the parent controls collection parentControl.Controls.Add(control); // if this is the first load (first time the page is loaded or // a new tab has been clicked) enable the viewstate again. Forgetting to // reenable the viewstate will controls to be loaded only once. Then // call the FirstLoad() method of the web user control for first time // loading tasks. if (isFirstLoad)
366
367
2. Add three more user controls to the \Admin directory: "CreateExams.ascx", "Questions.ascx", "ScheduleExams.ascx". These file names must exactly match the Value properties of the RadTabStrip on the admin page. 3. In the design view of each user control, type in the name of the page. This is just so we can see what control is loaded and that the user control swapping mechanism is working as expected.
368
Add the Telerik.ActiveSkill.Common namespace to the "Imports" (VB) or "uses" (C#) sections of code. Add IASControl to the class declaration. Right-click IASControl and select Implement Interface from the context menu. Inside the implementation, remove the the line that throws an exception so that the FirstLoad() method is empty (see code example below). In the AdminHome page, the FirstLoad() method is being called and will fail if this interface is not present. Once the IASControl is part of the declaration of the user control class, it must be implemented. The implementation generated by the UI will contain a NotImplementedException that must be removed so that we can load each of the user controls without failing.
The resulting code for the user control should now look something like this example: [VB] The UserControl with emtpy IASControl Implementation Imports System Imports System.Collections.Generic Imports Telerik.ActiveSkill.Common Namespace Telerik.ActiveSkill.UI.Admin Public Partial Class Categories Inherits System.Web.UI.UserControl Implements IASControl Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) End Sub #region IASControl Members Public Sub FirstLoad(ByVal args As Dictionary(Of String, String)) End Sub #End Region End Class End Namespace [C#] The UserControl with emtpy IASControl Implementation using System; using System.Collections.Generic; using Telerik.ActiveSkill.Common; namespace Telerik.ActiveSkill.UI.Admin { public partial class Categories : System.Web.UI.UserControl, IASControl { protected void Page_Load(object sender, EventArgs e) { }
369
If one of your user controls fails to load, don't forget to look at the Output window in Visual Studio. For example, if in the categories user control you place a textbox and then add another "less than" bracket to malform the tag, this error will show up in the output window. You must run the application in debug mode to get the output window display of the error message.
370
To create a new skin you typically start by copying an existing skin that's closest to the appearance you're looking for. You change the file names from something like "Calendar.Hay.css" to "Calendar.MyStyle.css".
371
2. In the web.config file add the following appSettings to globally set the skin for the entire application. This will set the skin for all RadControls that are not already defined by settings on the specific controls. [XML] Defining AppSettings for Skins in Web.Config <appSettings> <!-- RadControls for ASP.NET AJAX Step By Step --> <add key="Telerik.Skin" value="ActiveSkill"/> <add key="Telerik.EnableEmbeddedSkins" value="false"/> </appSettings>
372
13.6 Summary
In this chapter we built the Admin Home page, starting with the general layout and adding the code-behind required to swap user controls dynamically. We created each of the user controls and tested the dynamic swapping behavior. Finally we created a new custom ActiveSkill skin based on the standard Telerik "Black" skin and configured the application to use that skin throughout.
373
14.1 Objectives
Get acquainted with RadAsyncUpload as well as exploresome of its basicfeatures. Create a simple application to get confidence in using the RadAsyncUpload. Explore theRadAsyncUpload design time interface, including Smart Tag and the different skins that you can apply. Exploresome of the most importantpropertiesthat represent a sufficientpart ofthe RadAsyncUpload functionality. Learn some server-side coding techniques as well as get acquainted with theserver-side events of RadAsyncUpload. Explore some of the client-side methods and client-side events. Explore some advanced techniques, such as the three types of modules that RadAsyncUpload uses.
Temporary Files
374
Validation
Validation differs from RadUpload as it is now possible to validate size on the client, as long as there is Silverlight or Flash installed on the client's browser. If the validation fails, RadAsyncUpload will fire the OnClientValidationFailed.
Web Farms
In web farms, each server will need to use the same MachineKey as RadAsyncUpload uses it for encryption. Most web farms should already have their MachineKeys synchronized as this is the recommended approach for web farm deployment.
Use RadAsyncUpload to upload files. Use skins to provide a consistent look & feel.
You can find the complete source for this project at: \VS Projects\AsyncUpload\GettingStarted 1. We start by creating a new page and adding a RadAsyncUpload control to it. 2. Use the Smart Tag of the control to add RadScriptManager on the page:
375
3. It will automatically register the Telerik.Web.UI.WebResource.axd handler in the web.config file. This handler is used by both RadScriptManager and RadAsyncUpload. 4. You can change the Default skin of the RadAsyncUpload by choosing any of the predefined:
376
5. Set the TargetFolder property to the folder where you want the files to be automatically uploaded after the postback. The files are automatically and asynchronously uploaded to the folder specified by the TemporaryFolder property but are copied to the TargetFolder after the postback on the page. By default the TemporaryFolder is set to App_Data / RadUploadTemp folder. The files are uploaded with randomly generated unique names. [ASP.NET] Setting the target folder <telerik:RadAsyncUpload ID="RadAsyncUpload1" runat="server"></telerik:RadAsyncUpload> TargetFolder="TargetLocation"
6. Finally, add a button on the page which will postback. Run the application and select a file - you will see
377
Ajax Processing
Here is a sample Web page that uses RadAsyncUpload control and Ajax Processing to upload files. You can find the complete source for this project at: \VS Projects\AsyncUpload\AjaxProcessing Keep in mind that RadAsyncUpload:
Files are not directly uploaded to the page, but to a handler - Telerik.Web.UI.WebResource.axd. Uploaded files will be transferred to the TargetFolder when a postback occurs (meaning that you will need to add a "Submit" button, so that the files will be saved in the target folder). The page submission is not automatically blocked until the file upload completes. Uploaded files are stored in a temporary location - App_Data/RadUploadTemp by default. Windows and Forms Authentication require special handling.
Gets or sets the allowed file extensions for uploading. Specifies whether RadAsyncUpload displays an in-line progress next to each file being uploaded. Specifies the URL of the HTTP Handler for which the image will be served. Gets or sets the initial count of file input fields, which will appear in RadAsyncUpload(should be used only when MultipleSelection ="disabled") Gets or sets the size of the input field. Gets or setsmaximum file input fields that can be added to the control(should be used only when MultipleSelection ="disabled") Gets or sets the maximum file size allowed foruploadingin bytes. Specifies whether RadAsyncUpload allows selecting multiple filesin the File Selection dialog. Gets or sets the virtual path of the folder where RadAsyncUpload will automatically save the valid files after the upload completes. Sets upload configuration that has additional information. Provides access to the valid files uploaded by the RadAsyncUpload instance.
378
IsValid Allows you to specify whether the uploaded file is valid. If it is, RadAsyncUpload will automatically save it to the TargetFolder, if one is set. UploadedFile Provides reference to the file uploaded. UploadResultContainer object containing information sent from the RadAsyncUpload file handler.
The example below demonstrates how to prepare the uploaded file for sending as an e-mail attachment: [C#] Prepare the uploaded file for sending as an e-mail attachment void RadAsyncUpload1_FileUploaded(object sender, FileUploadedEventArgs e) { e.IsValid = !CheckUploadedFileValidity(); if (e.IsValid) { byte[] buffer = new byte[e.File.ContentLength];
379
Client-Side Events
RadAsyncUpload support the following client-side events:
380
OnClientAdded occurs when a row has just been added to the RadAsyncUpload control. OnClientFileSelected occurs when a file is selected in a file input control. OnClientFilesSelected occurs when files(s) are selected. These event can be cancelled, which will erase the selected files collection. OnClientFileUploading occurs when a file upload has started uploading. OnClientFileUploaded occurs when a file has finished uploading. OnClientValidation occurs when a uploaded file is about to be removed from the uploaded files collection. OnClientFileUploadRemoving occurs before a selected file is about to be removed from the uploaded files collection. The event can be cancelled. OnClientFileUploadRemoved occurs when a uploaded file is about is removed from the uploaded files collection. OnClientFileUploadFailedoccurs when a file upload has failed due to an HTTP or server-side error. OnClientProgressUpdating occurs each time the in-line progress indicator is being updated.
To use these events, simply write a javascript function that can be called when the event occurs. Then assign the name of the javascript function as the value of the the corresponding property (just like the example above).
14.8 Summary
In this chapter you looked at the RadAsyncUpload control andgot acquainted withsome of the powerful features that it provides. You created a simple application using the control. You alsolooked at some importantserver-side properties of the RadAsyncUpload as well as the FileUploaded server-side event. You exploredthe client-sidemethods, that the RadAsyncUpload possesses and that would be very helpful if you need to implement an additional functionality to the RadAsyncUpload control. Finally, you learned how the RadAsyncUpload works when using the different types of modules.
381
15.1 Objectives
Explore the features of the RadComboBox control. Create a simple application to get confidence in using the combo box and to see the difference between static items and data-bound items. Explore the combo box design time interface, including Smart Tag, Properties Window, Property Builder, and Template Design surface. Explore principal properties and groups of properties wheremost of the functionality is found. Learn to use special combo-box features such as templates, custom attributes, and load-on-demand. Learn server-side coding techniques,including an exploration of how to work with the items collection, an examination of important server-side events, and a look at the properties and methods for sorting the drop-down list. Explore some of the client-side methods for working with the items collection and some of the client-side events, with special attention to the events you can use with the load-on-demand feature. Explore some advanced techniques, such as implementing custom sort criteria, adding input controls to an item template, and enabling virtual scrolling without allowing custom text to be entered, and implementing a Web service to supply items on demand.
15.2 Introduction
You are probably already familiar with the ASP.NET DropDownList control. It lets users select options from a drop-down list of items. The RadComboBox control is a similar control, but it gives you far more power and flexibility. Like all RadControls, RadComboBox lets you assign a Skin to instantly change the appearance to one that harmonizes with the overall look-and-feel of your Web page. Your control over the look-and-feel does not stop there. You can also add images to the items in the drop-down list, or even use templates for complete control over the appearance of items. You can even add animated effects to the way the list drops down and closes back up.
Unlike the ASP.NET DropDownList control, which restricts users to selecting only items from the list, RadComboBox can optionally allow users to type in entries that are not in the list. When the combo box is configured to let users enter custom text in this manner, you can provide an "empty" message to the drop-down list, similar to the empty message that you saw on the input RadControls. If you need to work with a very long list of items, RadComboBox can help users navigate that list with its autocomplete feature, which automatically scrolls the list and highlightsthe first itemthat matches the currently entered text.Alternately, you can use the filtering feature, which limits the list to items that contain the currently entered text, and highlights the matching text. You can even configure the combo box to load items
382
You can find the complete source for this project at: \VS Projects\ComboBox\GettingStarted
383
Set the Text property to "Rainbow:". Set the IsSeparator property to true.
5. Click the "Add Item" button again to add a second item. Set its properties as follows:
Set the Text property to "Red". Set the ToolTip property to "Select 'Red'". Set the ImageUrl property to "~/Images/Red.png".
Set the Text property to "Orange". Set the ToolTip property to "Select 'Orange'". Set the ImageUrl property to "~/Images/Orange.png".
7. Repeat this process for four more buttons, using the colors "Yellow", "Green", "Blue", and "Violet". 8. Add another item and set its Text property to "Monochrome:" and its IsSeparator property to true. 9. Add another item and set its properties as follows:
Set the Text property to "Black". Set the ToolTip property to "Select 'Black'". Set the ImageUrl property to "~/Images/Black.png".
10. Add a last "color" item, using the color "White". 11. Click OK to exit the Item Builder.
384
Set the DataTextField property to "TerritoryDescription". Set the DataValueField property to "TerritoryID".
The combo box is now bound to the data source. 11. While you are in the Properties Window, set a few more properties:
Expand the ExpandAnimation property and set the Type sub-property to "OutBounce". Expand the CollapseAnimation property and set the Type sub-property to "InBounce". Set the MarkFirstMatch property to true.
Smart Tag
The RadComboBox Smart Tag contains a few control-specific entries in addition to the standard Ajax Resources, Skin selection, and Learning center sections.
385
At the top of the Smart Tag, the Choose Data Source drop-down lets you bind the combo box to a data source control already on the Web page, or launch the DataSource Configuration Wizard to create and configure a new data source control. Once the combo box is bound to a data source, the Smart Tag changes to include Configure Data Source and Refresh Schema links beneath the Choose Data Source drop-down. Below the Choose Data Source drop-down, the Build RadComboBox... link brings up the RadComboBox Item Builder, where you can add statically declared items to the combo box. At the bottom of the Smart Tag, the Edit Templates link lets you bring up the Template Design Surface, where you can design a template for combo box items.
Properties Window
At design time, you can use the Properties Window to configure almost every aspect of the combo box. (A notable exception is the creation of templates.) As with the other controls we have seen, let us look at the most important properties of the combo box.
Specifying Items
Probably the most important property of the combo box is the one that specifies what items appear in the drop-down list. What property you choose for this task depends on whether you want to load items from a database:
If you want to load items from a database, RadComboBox supports the standard data-binding properties (DataSourceID and DataMember), which you have already seen in the chapter on Data Binding. That chapter also introduced you to the AppendDataBoundItems property, which lets you combine data-bound items with statically declared items, and the alternate approach to binding of using the DataSource property and the DataBind method in the code-behind. When binding RadComboBox to a data source, use
386
If you want to use statically declared items, you can use the Items property to bring up the RadComboBox Item Builder. The Item Builder is described in more detail below.
When MarkFirstMatch is false, the AllowCustomText property has a major effect on the behavior of the combo box. When AllowCustomText is false, typing a character in the text box selects the first item from the drop-down list that starts with the entered character. If another item starts with the same character, it can be selected by typing the character a second time. When AllowCustomText is true, typing in the text area selects exactly the text that is typed, regardless of whether it matches a string in the list. When MarkFirstMatch is true, typing a character in the text box always selects the first item from the drop-down list that matches the character. However, the text area remains editable, so that more characters can be typed, further limiting the number of strings that match. If AllowCustomText is false, any characters that do not match a string in the list are ignored. If AllowCustomText is true, entering a character that does not match any items in the list causes the combo box to behave in the same way as when the auto-complete feature is not turned on.
When MarkFirstMatch is true, two other properties influence the behavior of the auto-complete feature.
AutoCompleteSeparator enables the user to select multiple items from the list. It specifies the character that separates list items. Typically, AutoCompleteSeparator is set to a character such as "," or ";". After the user enters the separator character, the next character typed begins a new selected item, and the list items are matched to the text that follows the separator. EnableTextSelection controls whether the unentered text of the matched list item is selected when the combo box adds it to the edit box as a result of the auto-complete feature. When EnableTextSelection is true, the unentered text is selected. This is most useful for a single-selection combo box (with no AutoCompleteSeparator), because the next character that the user types simply refines the search. When EnableTextSelection is false, the rest of the matched list item is not selected, and the cursor appears at the end of the string. This is most useful for a multi-selection combo box, as the cursor is placed conveniently for typing the separator character.
Another feature that is similar to the auto-complete feature is the use of filters. You can turn on filtering by setting the Filter property to "StartsWith" or "Contains". When Filter is "StartsWith", typing in the text area causes the list to filter out all items that do not start with the string in the text area. The portion of list items that matches the string in the text area is highlighted. When Filter is "Contains", the combo box uses a broader criterion for matching the string in thetext area.If the entered text falls anywhere within a list item, it is kept in the list. Once again, the matching text is highlighted. Unlike the MarkFirstMatch property, which uses the IsCaseSensitive property to determine whether to match items in a case-sensitive manner, the Filter property is always case-insensitive.
387
Specifying appearance
As with all RadControls, you can use the Skin property to change the overall look of the combo box. In addition, a number of properties influence the layout of combo box parts. The Width property specifies the width of the text area plus drop-down arrow, while the DropDownWidth specifies the width of the drop-down list. The OffsetX and OffsetY properties let you control the position of the drop-down list. The Height property lets you control the height of the drop-down list. When you use the Filter feature, it is a good idea to explicitly set the Height property. Otherwise, the dropdown list will be sized based on its contents the first time it opens, and if that is a small filtered list, the combo box can become hard to use. You can hide the drop-down arrow by setting the ShowToggleImage property to false. When hiding the dropdown arrow, be sure that the ShowDropDownOnTextBoxClick property is true, or the user will not be able to open the drop down list! You can move the drop-down arrow so that it appears to the left of the text box by changing the RadComboBoxImagePosition property to "Left". To configure the combo box for a right-to-left locale, don't bother using the RadComboBoxImagePosition property. Instead, add the dir="rtl" attribute to the combo box. The dir="rtl" attribute moves the position of item text and images as well, and even moves punctuation characters in the item text to the other side.
388
Eachitemhas its own set of properties: Text is the string that displays in the drop-down list,IsSeparator specifies whether the user can select the item, ImageUrl isthe path to an image file that will display next to the Text, and DisabledImageUrl is the path to an image file to use when the item is disabled.These four properties control the basic appearance of the list items. Youmay also want to set the ToolTip property to assign a tool tip for the item, or use the Selected and Enabled propertiesto specify the state of the item when the Web page first loads.Another common property is the Value property, which associates a value with the item that you can then use when programming with the combo box.
389
You can find the complete source for this project at: \VS Projects\ComboBox\Templates Both the HeaderTemplate and the ItemTemplate are formatted using a <table> with fixed width columns. This way, the header labels line up with the columns in the drop-down list. The FooterTemplate starts out empty, as the text it displays is populated in client-side code. [ASP.NET] ComboBox with templates <telerik:RadComboBox ID="RadComboBox1" Runat="server" DropDownWidth="350px" Width="250px" Skin="Outlook" DataSourceID="SqlDataSource1" HighlightTemplatedItems="True" onitemdatabound="RadComboBox1_ItemDataBound" onclientselectedindexchanged="IndexChanged" onclientload="InitComboFooter" > <HeaderTemplate> <table style="width: 315px; text-align: left"> <tr> <td style="width: 95px;">Last Name</td> <td style="width: 95px;">First Name</td> <td style="width: 125px;">Title</td> </tr> </table> </HeaderTemplate>
390
391
You can find the complete source for this project at: \VS Projects\ComboBox\TemplateControl 1. Create a Web Application and add a ScriptManager to the default page. 2. Add a RadComboBox to the default page.
Set the Skin property to "Hay". Set the ShowDropDownOnTextboxClick property to false. Set the DropDownWidth property to "230px".
3. Bring up the RadComboBox Item Builder and add a single item with its Text property set to an empty string. 4. Click on the Edit Templates link in the Smart Tag to bring up the Template Design Surface. 5. Drag a RadCalendar control from the Tool Box onto the Template Design Surface.
Set the AutoPostBack property to true Set the EnableMultiSelect property to false.
392
Set the ShowRowHeaders property to false. Set the TitleFormat property to "MMM yyyy".
6. Go to the code-behind for the default page. At the top of the page, in addition to an Imports or using statement for "Telerik.Web.UI", add one for "Telerik.Web.UI.Calendar". Then add the following method: [VB] SelectionChanged Protected Sub RadCalendar1_SelectionChanged(ByVal sender As Object, ByVal e As SelectedDatesEventArgs) Dim calendar As RadCalendar = DirectCast(sender, RadCalendar) 'Update the combo box item Text 'The combo box will then assign its value accordingly RadComboBox1.SelectedItem.Text = [String].Format("{0}/{1}/{2}", calendar.SelectedDate.Month, calendar.SelectedDate.Day, calendar.SelectedDate.Year) End Sub [C#] SelectionChanged protected void RadCalendar1_SelectionChanged(object sender, Telerik.Web.UI.Calendar.SelectedDatesEventArgs e) { RadCalendar calendar = (RadCalendar)sender; // Update the combo box item Text // The combo box will then assign its value accordingly RadComboBox1.SelectedItem.Text = String.Format("{0}/{1}/{2}", calendar.SelectedDate.Month, calendar.SelectedDate.Day, calendar.SelectedDate.Year); } Note that this event handler assigns the Text property of the single combo box item. 7. Back in the Design window for the Web page, assign the method you just created as the SelectionChanged event handler of the RadCalendar control in the template, and then end template editing. 8. Press Ctrl-F5 to run the application. When you expand the drop-down list, the combo box displays the calendar, and when you select a date, the selected text of the combo box updates to the value you assigned in the event handler. However, you will also notice that there are some rough edges. Before the SelectionChanged event handler sets the text, a different value sometimes appears, and there is a jarring disruption when the page reloads on the postback. Shut down the running application so that we can fix these irritations. 9. Bring up the Template Design Surface again, and on the RadCalendar control's Properties Window, expand the ClientEvents property. Set the OnDateSelecting sub-property to "OnDateSelecting" and the OnDateClick sub-property to "OnDateClick". Then end template editing. 10. Switch to the Source window, and add the following script block to the form. [ASP.NET] Calendar client-side events <script type="text/javascript"> // prevent the click from propagating up // to the combo box item function OnDateClick(sender, args) { args.get_domEvent().stopPropagation(); } // Before the calendar causes a postback // call attachDropDown so that the postback // can be converted to a callback function OnDateSelecting(sender, args) { if (args.get_isSelecting()) { var combo = $find("RadComboBox1"); combo.attachDropDown();
393
As an alternate approach to using the attachDropDown() method, you can use the client-side events of the calendar to update the combo box text rather than the server-side SelectionChanged event. 11. Return to the Design view. Drag a RadAjaxManager from the Tool Box onto the Web page. Configure the AJAX manager so that requests can be initiated by the combo box item. Set the combo box as the updated control. [ASP.NET] RadAjaxManager <telerik:RadAjaxManager ID="RadAjaxManager1" runat="server"> <AjaxSettings> <telerik:AjaxSetting AjaxControlID="i0"> <UpdatedControls> <telerik:AjaxUpdatedControl ControlID="RadComboBox1" /> </UpdatedControls> </telerik:AjaxSetting> </AjaxSettings> </telerik:RadAjaxManager> 12. Press Ctrl-F5 to run the application again. Now, when you select a date in the calendar, the combo box updates smoothly.
Custom Attributes
RadComboBox supports the use of custom attributes. You have already seen custom attributes in the chapter on Data Binding, and saw how they could be set in an ItemDataBound event handler. You can also set custom attributes declaratively when using statically-declared items. The following example illustrates using declarative custom attributes with a combo box. The custom attributes are used to bind elements in an item template.
394
395
Load-on-demand
When the data source for a combo box includes a very large number of items, it may be impractical to display them all at once. For one thing, too many entries make it hard for the user to find the correct choice, and for another, loading all of those elements at once can hurt performance. The first issue may be solved by using filters, but the only way to solve the second is to load items only as they are needed. To enable the combo box to load items only as they are needed, set the EnableLoadOnDemand property to true. When load-on-demand is enabled, the combo box always allows the user to enter custom text, regardless of the value of the AllowCustomText property. This is necessary so that the user can enter text that does not appear in the drop-down list, which then causes the combo box to load matching items. Gotcha! When EnableLoadOnDemand is true, do not try to read theItems property of the combo box in the code-behind. Due to performance issues, the Items property is not updated to reflectitems loaded on demand. The load-on-demand mechanism works as follows: 1. The user types in the text area of the combo box or clicks on the drop-down arrow. 2. In response, the combo box automatically generates an AJAX callback to request a new list. The new list of items can be supplied either by a server-side ItemsRequested event handler or by a Web Service that is identified by the WebServiceSettings property. 3. The drop-down list opens, displaying the new list of items. One important thing to notice here is that the load-on-demand mechanism uses an AJAX callback, not a postback. If the ItemsRequested event handler makes any changes to controls on the Web page (other than the combo box list of items), they are immediately lost, because they are not identified as updated controls for the callback. Another consequence is that any code in the Page_Load event handler that is protected by a check of the Page.IsPostBack property will execute every time the combo box requests a new list of items, since callbacks do not change the IsPostBack property. To prevent code in the Page_Load event handler from executing every time the combo box requests a new list of items, check the Page.IsCallback property as well as the Page.IsPostBack property.
396
The ItemsRequested event handler checks whether the combo box contains any text, and if so, it generates a database query to retrieve matching items and adds them to the combo box. In this example, checking for an empty text string is probably not that important, but in cases where the number of items is huge, you would probably not want to handle the request that fetches the entire data set. After the ItemsRequested event handler creates new items and adds them to the Items property of the combo box,it causes the thread to sleep for 100 milliseconds less than the item request timeout period. Obviously you would not want to do this in a real application,but this example inserts the command so that you can see the effects of item caching. [VB] Adding items in the ItemsRequested event handler Protected Sub RadComboBox1_ItemsRequested(ByVal o As Object, ByVal e As RadComboBoxItemsRequestedEventArgs) ' only add items if there is text to match If e.Text = [String].Empty Then ' open a connection to the database Dim dbCon As New SqlConnection(NWConnectionString) dbCon.Open() ' the query uses LIKE to match the entered text Dim sql As String = "SELECT * from Customers WHERE CompanyName LIKE '" + e.Text + "%'" ' create a data adapter and use it to fetch data into a table Dim adapter As New SqlDataAdapter(sql, dbCon) Dim dt As New DataTable() adapter.Fill(dt) dbCon.Close() ' use the table to add items to the combo box For Each row As DataRow In dt.Rows Dim item As New RadComboBoxItem(row("CompanyName").ToString()) RadComboBox1.Items.Add(item) Next 'Simulate a lengthy process so that the effects of caching can be seen Threading.Thread.Sleep(RadComboBox1.ItemRequestTimeout - 100) End If End Sub [C#] Adding items in the ItemsRequested event handler protected void RadComboBox1_ItemsRequested(object o, RadComboBoxItemsRequestedEventArgs e) {
397
When Virtual Scrolling or the Show More Results box is enabled, the combo box does not clear the items list before generating a callback to request items. This is in contrast to the way load-on-demand works when these features are not enabled.
398
It checks the e.NumberOfItems property to determine the number of items already loaded in the combo box. It sets the e.EndOfItems property when it detects that there are no more items to fetch. By setting e.EndOfItems, the event handler turns off the virtual scrolling mechanism. (e.EndOfItems does not affect the Show More Results box) It sets the e.Message property to a string describing the items that were fetched. The e.Message property sets the text that appears in the Show More Results box. If the event handler does not set this text, the Show More Results box includes only the link.
You can find the complete source for this project at: \VS Projects\ComboBox\VirtualScrolling [VB] Adding the next batch of items in the ItemsRequested handler Protected Sub RadComboBox1_ItemsRequested(ByVal o As Object, ByVal e As RadComboBoxItemsRequestedEventArgs) Handles RadComboBox1.ItemsRequested Dim connectionString As String = ConfigurationManager.ConnectionStrings ("NorthwindConnectionString").ConnectionString ' open a connection to the database Dim dbCon As New SqlConnection(connectionString) Try dbCon.Open() Dim itemsPerRequest As Integer = 10 Dim itemOffset As Integer = e.NumberOfItems Dim endOffset As Integer = itemOffset + itemsPerRequest ' the query only fetches the required number of records Dim sql As String = "SELECT top " + endOffset.ToString() + "ProductName FROM [Products by Category] where ProductName LIKE '" + e.Text + "%'" ' create a data adapter and use it to fetch data into a table Dim adapter As New SqlDataAdapter(sql, dbCon) Dim dt As New DataTable() adapter.Fill(dt) ' if we did not get the requested number of records ' we have reached the end of the data set ' set EndOfItems to signal this If dt.Rows.Count < endOffset Then e.EndOfItems = True End If ' if there are no items, set the message for the more results box If dt.Rows.Count = 0 Then e.Message = "No items"
399
400
FindItemByText, which returns a reference to an item given the value of its Text property. FindItemByValue, which returns a reference to an item given the value of its Value property. FindItemIndexByText, which returns the index of an item given the value of its Text property. FindItemIndexByValue, which returns the index of an item given the value of its Value property.
Once you have located an item, you can use its properties to change its value, select it, disable it, delete it, and so on. The following example illustrates some of these methods. It uses the FindItemByText method to determine whether the string a user types in the text area of a combo box is already in the drop-down list. If not, it adds an item to the list with its Text property set to the new string and its Value property set to reflect the position of the new item. Next, the Value property of the item in the drop-down list (either the matching item that was found or the newly entered item) is passed to the FindItemIndexByValue method of a second combo box. If an item with a matching value is found, that corresponding item is selected.
401
You can find the complete source for this project at: \VS Projects\ComboBox\ServerSide [VB] Working with items Protected Sub RadComboBox1_TextChanged(ByVal sender As Object, ByVal e As EventArgs) Handles RadComboBox1.TextChanged ' If the string is not in combo box 1, add it Dim item As RadComboBoxItem = RadComboBox1.FindItemByText(RadComboBox1.Text) If item Is Nothing Then ' create a new item with Text set to the text in the input area ' and value set to the position of the new item item = New RadComboBoxItem(RadComboBox1.Text, (RadComboBox1.Items.Count + 1).ToString()) ' add it to combo box 1 RadComboBox1.Items.Add(item) End If ' If an item with the same value is in combo box 2, select it Dim value As String = item.Value Dim index As Integer = RadComboBox2.FindItemIndexByValue(value) If RadComboBox2.SelectedIndex <> index AndAlso index >= 0 Then RadComboBox2.Items(index).Selected = True End If End Sub [C#] Working with items protected void RadComboBox1_TextChanged(object sender, EventArgs e) { // If the string is not in combo box 1, add it RadComboBoxItem item = RadComboBox1.FindItemByText(RadComboBox1.Text); if (item == null) {
402
403
You can find the complete source for this project at: \VS Projects\ComboBox\ServerSelectedIndex [VB] Updating controls in the SelectedIndexChanged event Protected Sub RadComboBox1_SelectedIndexChanged(ByVal o As Object, ByVal e As RadComboBoxSelectedIndexChangedEventArgs) Handles RadComboBox1.SelectedIndexChanged ' Display the last selection and the new selection in the label Label1.Text = "You just read about " + e.OldText + ". Now read about " + e.Text + ": " ' update the image to the one associated with the current item Image1.ImageUrl = RadComboBox1.SelectedItem.ImageUrl ' use the new value to index the appropriate blurb. RadTextBox1.Text = Blurbs(System.Int16.Parse(e.Value)) End Sub [C#] Updating controls in the SelectedIndexChanged event protected void RadComboBox1_SelectedIndexChanged(object o, RadComboBoxSelectedIndexChangedEventArgs e) { // Display the last selection and the new selection in the label Label1.Text = "You just read about " + e.OldText + ". Now read about " + e.Text + ": "; // update the image to the one associated with the current item Image1.ImageUrl = RadComboBox1.SelectedItem.ImageUrl; // use the new value to index the appropriate blurb.
404
Sorting items
You can sort the items of RadComboBox to make it easier for users to locate the item they want in the dropdown list. To enable sorting, set the Sort property of the combo box to "Ascending" or "Descending", depending on the order you want. By default, sorting is case sensitive, but you can change that by setting the SortCaseSensitive property to false. When the Sort property is set to "Ascending" or "Descending", you can sort the items by calling the combo box's SortItems method, or by calling the Sort method of the Items collection. Both methods do the same thing: they sort the items based on their Text property values. The following walk-through illustrates the use of the Sort and SortItems methods. You can find the complete source for this project at: \VS Projects\ComboBox\Sorting
405
406
You can also sort items using a custom sort criterion. See the How-To section for an example of how this is done.
407
You can find the complete source for this project at: \VS Projects\ComboBox\ClientSide [JavaScript] Manipulating the items collection function ChangeDropDownList(sender) { // check whether the text box has any text var text = sender.get_value(); if (text.trim() != "") { // get a reference to the combo box var combo = $find("<%= RadComboBox1.ClientID %>"); // find the matching combo box item var item = combo.findItemByText(text); // call trackChanges so that the changes can persist combo.trackChanges(); // if the item is in the list, remove it if (item) { combo.get_items().remove(item); } else { // if the item is not in the list, add it var comboItem = new Telerik.Web.UI.RadComboBoxItem(); comboItem.set_text(text); combo.get_items().add(comboItem); comboItem.select(); } // commit the changes combo.commitChanges(); } } Notice in the code above that before making any changes to the items collection, the function calls the combo box's trackChanges() method. After the changes are complete, it calls the commitChanges() method. These two methods are important when working with the items collection. If you do not surround any changes that you make to the items collection with calls to trackChanges() and commitChanges(), the changes are lost the next time the page executes a postback. Any changes made in client-side code after the call to trackChanges() can be reviewed in server-side code by reading the server-side ClientChanges property. ClientChanges is a collection of ClientOperation objects that describe each client-side change that was made.
408
You can find the complete source for this project at: \VS Projects\ComboBox\ClientEvents [ASP.NET] ComboBox with client events <script type="text/javascript"> // OnClientFocus handler function OpenDropDownOnFocus(sender, args) { // if the text is not set if (sender.get_text() == ""); // open the drop down list sender.showDropDown(); } // OnClientDropDownOpened handler function RestoreEmptyMessage(sender, args) { // if the text is not set if (sender.get_text() == "") // set it back to the empty message sender.set_text(sender.get_emptyMessage()); } // OnClientDropDownClosed handler function RestoreEmptyString(sender, args) { // if the text is still the empty message if (sender.get_text() == sender.get_emptyMessage()) // set it back to an empty string
409
Before the callback occurs, the OnClientItemsRequesting event lets you provide additional context information to the event handler or Web service that supplies items, or even cancel the event to prevent the callback from occurring. If the callback fails for some reason, the OnClientItemsRequestFailed event lets you provide your own response, in addition to or instead of the default error message. If the callback is successful, the OnClientItemsRequested event lets you provide your own post-processing.
The following example illustrates the use of these three events. The example uses two combo boxes: one bound to a data source and the other getting its items using the load-on-demand mechanism. The combo box that loads its items on demand uses the currently selected item in the first combo box to provide additional context information to the server-side ItemsRequested handler. As a result, the items list of the second combo box displays only items associated with the selected item in the first combo box. Entering text in the second combo box further limits this list to items that match the entered text.
You can find the complete source for this project at: \VS Projects\ComboBox\ClientLoadOnDemand Before looking at the load-on-demand related events, let us first look at the first combo box. When the user changes the selected item in the first combo box, the drop-down list and text of the second combo box become invalid. To handle this, the first combo box has an OnClientSelectedIndexChanged handler that clears the text and drop-down list of the second combo box. As an added nicety, the event handler moves focus to the text area of the second combo box: [JavaScript] Clearing the second combo box when the first changes
410
411
412
The last client-side event related to load-on-demand is OnClientItemsRequested, which occurs once the dropdown list is populated with new items. In this example, the event handler selects the first item in the list if the user has already entered text before opening the drop-down list: [JavaScript] Selecting the first item in the new list function ItemsRequested(sender, args) { // get the new list of items var items = sender.get_items(); // if the user has started entering some text // and the new list of items is not empty if (sender.get_text() != "" && items.get_count() > 0) // select the first item items.getItem(0).select(); }
413
You can find the complete source for this project at: \VS Projects\ComboBox\HowToCustomSort To implement the custom sort, the application first defines a class that implements the IComparer interface. The IComparer interface defines a single method, Compare, which compares two objects: [VB] CustomSort class Public Class CustomSort Implements IComparer Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare Dim p1 As RadComboBoxItem, p2 As RadComboBoxItem ' first make sure the items are of type RadComboBoxItem If TypeOf x Is RadComboBoxItem Then p1 = TryCast(x, RadComboBoxItem) Else Throw New ArgumentException("Object is not of type RadComboBoxItem.") End If If TypeOf y Is RadComboBoxItem Then p2 = TryCast(y, RadComboBoxItem) Else Throw New ArgumentException("Object is not of type RadComboBoxItem.") End If ' get the combo box Dim combo As RadComboBox = p1.ComboBoxParent ' get the Region attribute for each item Dim a1 As String = p1.Attributes("Region")
414
415
416
To implement this, the combo box uses an item template with a RadDateInput in it. For all but the last item, the date input control has its ReadOnly property set to true. On the last item, the ReadOnly property is set to "False", allowing the user to enter a custom value, and has its MinDate property set to enforce a range. The template suppresses mouse click events from bubbling up when the click occurs in the last text box. You can find the complete source for this project at: \VS Projects\ComboBox\HowToInputInTemplate The declaration for the combo box includes a custom attribute to indicate the "ReadOnly" status of items: [ASP.NET] RadComboBox declaration <telerik:RadComboBox ID="RadComboBox1" runat="server" > <Items> <telerik:RadComboBoxItem runat="server" Text="1/1/2005" Value="1/1/2005" ReadOnly="True" /> <telerik:RadComboBoxItem runat="server" Text="1/1/2006" Value="1/1/2006" ReadOnly="True" /> <telerik:RadComboBoxItem runat="server" Text="1/1/2007" Value="1/1/2007" ReadOnly="True" /> <telerik:RadComboBoxItem runat="server" Text="" ReadOnly="False" /> </Items> <ItemTemplate> <div onclick="ClickTemplate(event)"> <telerik:RadDateInput ID="RadDateInput1" runat="server" Width="97%" > <ClientEvents OnValueChanged="ValueChanged" OnFocus="FocusItem" /> </telerik:RadDateInput> </div> </ItemTemplate> </telerik:RadComboBox> Note that the RadDateInput control in the template does not have its SelectedDate, ReadOnly, or MinDateproperties set. This is done in the Page_Load event handler: [VB] Initializing template controls Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Dim i As Integer = 0 While i < RadComboBox1.Items.Count Dim item As RadComboBoxItem = RadComboBox1.Items(i) ' get the date input inside the template Dim di As RadDateInput = DirectCast(RadComboBox1.Items(i).FindControl("RadDateInput1"), RadDateInput) If Not di Is Nothing Then ' set the ReadOnly property to match the item attribute
417
418
419
Because each control name begins with the string "Rad", it does not make sense to generate a callback unless the text is an empty string or a string of at least four characters. A client-side ItemsRequesting event handler ensures that the callback only occurs when it makes sense, by cancelling the request when the text is one, two, or three characters long. [JavaScript] Cancelling the request in the ItemsRequesting handler function ItemsRequesting(sender, args) { if ((sender.get_text().length < 4) && (sender.get_text() != "")) args.set_cancel(true); } You can find the complete source for this project at: \VS Projects\ComboBox\HowToLimitItemRequests
420
To populate the drop-down list when it first opens, the application uses an OnClientDropDownOpening event handler. The event handler calls the requestItems() method, which initiates a callback to fetch the first set of items. [JavaScript] Initiating an item request when the drop-down opens function OnClientDropDownOpeningHandler(sender, args) { // initiate an item request // first parameter is the text // second parameter is whether to append items sender.requestItems("", true); } Because virtual scrolling requires a scroll bar to be present, the Height property is set so that the first set of items do not all fit in the drop-down list. This ensures that a scroll bar appears when the first set of items is loaded. [ASP.NET] Combo box declaration <telerik:RadComboBox ID="RadComboBox1" runat="server" Skin="Hay" DropDownWidth="200px" Height="200px" AllowCustomText="false" EnableVirtualScrolling="true" OnClientDropDownOpening="OnClientDropDownOpeningHandler" OnItemsRequested="RadComboBox1_ItemsRequested" > </telerik:RadComboBox> You can find the complete source for this project at: \VS Projects\ComboBox\HowToVirtualScrollNoCustomText
421
Instead of implementing a server-side ItemsRequested event handler, the combo box can load items on demand from a Web service. To configure the combo box to use a Web service, set the WebServiceSettings property, giving the name of the Web Method and the path to the Web Service: [ASP.NET] Combo box that uses a Web service for load-on-demand <telerik:RadComboBox ID="RadComboBox1" Runat="server" Skin="Vista" EnableLoadOnDemand="True" ShowMoreResultsBox="True" > <WebServiceSettings Method="GetCompanyNames" Path="ComboWebService.asmx" /> </telerik:RadComboBox> When implementing the Web Service, any Web Method that supports the load-on-demand mechanism must take a single parameter, which supplies context information about the request. This parameter is of type RadComboBoxContext, but it can also be cast to IDictionary to read context information that is added in an OnClientItemsRequesting event handler. Gotcha! Because the context parameter is an IDictionary value, you cannot run the Web Service directly from within Visual Studio. When running the example, select Default.aspx before hitting F5 or Ctrl-F5. You have a choice of two types for the return value:
You can always return a value of type RadComboBoxData. This type includes an Items property thatlists information about each item that is supplied. In addition, your Web Method can set the Message and EndOfItems properties if you are supporting virtual scrolling. If your Web Method does not support virtual scrolling, you can return an array of RadComboBoxItemData objects. (This is the type of the Items property of RadComboBoxData.)
The following example illustrates these different options. It implements a Web Service with two Web Methods, "GetCustomers" and "GetCompanyNames". Both produce a list of items from the Northwind "Customers" table.
422
The first Web Method ("GetCustomers") expects the user to supply context information in an OnClientItemsRequesting handler: therefore, it casts the context parameter toIDictionary. Because it does not support virtual scrolling, it returns an array of RadComboBoxItemData. [VB] Servicing requests that include extra context information <WebMethod()> _ Public Function GetCustomers(ByVal context As RadComboBoxContext) As RadComboBoxItemData() ' create the connection Dim connection As New SqlConnection(ConfigurationManager.ConnectionStrings ("NorthwindConnectionString").ConnectionString) ' read the filter from context Dim filterString As String = (TryCast(context, IDictionary(Of String, Object))) ("FilterString").ToString() ' create a command, fetching customers that match filterString Dim selectCommand As New SqlCommand(" SELECT * FROM Customers WHERE CompanyName LIKE '" + filterString + "%'", connection) ' fill a data table with the customers Dim adapter As New SqlDataAdapter(selectCommand) Dim customers As New DataTable() adapter.Fill(customers) ' create a list of RadComboBoxItemData to hold new items Dim result As New List(Of RadComboBoxItemData)(customers.Rows.Count) ' create an item for every row in the table For Each row As DataRow In customers.Rows Dim itemData As New RadComboBoxItemData() itemData.Text = row("CompanyName").ToString() itemData.Value = row("CompanyName").ToString() result.Add(itemData) Next ' convert the list to an array, and return it Return result.ToArray() End Function [C#] Servicing requests that include extra context information [WebMethod] public RadComboBoxItemData[] GetCustomers(RadComboBoxContext context)
423
424
425
15.9 Summary
In this chapter you looked at the RadComboBox control and saw some of the powerful features it provides. You created a simple application that populatedone combo box with statically declared items and another with items loaded from a data source. At the same time, you looked at some properties of the combo box and combo box items. You looked at the design time support for the combo box and explored many of the properties and groups of properties you can use to configure the combo box at design time. You learned about the different types of template you can use with a combo box, and how to work with combo box custom attributes. You also learned about the load-on-demand mechanism, and saw how it can be used with virtual scrolling or a "More Results" box to improve performance.
426
427
16.1 Objectives
Explore the features of the RadTreeView control. Create a simple application to get confidence in using the tree view and to see how to build a node hierarchy either statically or using data supplied from a data source. Explore the tree view design time interface, including Smart Tag, Properties Window, Property Builder, Collection Editors and Template Design surface. Explore principal properties and groups of properties where most of the functionality is found. Learn to use special tree view features such as node editing, check boxes, drag-and-drop, and node context menus. Learn server-side coding techniques, including traversing the node hierarchy to make a change to all parent nodes or all child nodes, building the tree view dynamically in code to accommodate data from multiple database tables, and handling server-side events. Explore some of the client-side methods of the tree node and tree view client-side objects, learn to implement the 'radio button' pattern for state changes, and learn to expand the number of client side events you can respond to by accessing the DOM object for the tree view. Learn to wrap the text that appears on tree view nodes and to add controls directly to tree nodes without using templates. Explore the different options for using load-on-demand to improve performance.
16.2 Introduction
You are undoubtably aware of tree view controls, whichappear in many desktop applications. For example, the Solution Explorer in Visual Studio is a tree view control that lets you navigate the components of your project and perform basic operation such as adding and deleting new components. RadTreeView lets you add the same capability to your Web applications. It displays a hierarchy of items that you can declare statically or load from a data source.
RadTreeView combines the highly efficient rendering of RadControls for ASP.NET AJAX with a powerful set of features. You can use the familiar skinning capabilities to make the tree view fit in with the look and feel of
428
You can find the complete source for this project at: \VS Projects\TreeView\GettingStarted
429
Set the Text property to "RadControls for ASP.NET AJAX". Set the Checkable property to false.
5. Click the "Add child item" button again to add a child node to the root node. Set its properties as follows:
Set the Text property to "Navigation". Set the Checkable property to false. Set the ToolTip property to "Navigation controls".
6. With the "Navigation" node selected, click the "Add child item button five times to add five child nodes.
On the first, set the Text property to "RadMenu" and the ImageUrl property to "~/Images/RadMenu.png". On the second, set the Text property to "RadContextMenu" and the ImageUrl property to "~/Images/RadMenu.png". On the third, set the Text property to "RadTabStrip" and the ImageUrl property to "~/Images/RadTabStrip.png". On the fourth, set the Text property to "RadPanelBar" and the ImageUrl property to "~/Images/RadPanelBar.png". On the fifth, set the Text property to "RadToolBar" and the ImageUrl property to "~/Images/RadToolBar.png".
7. Select the root item and click the "Add child item" button to add a second child node to the root node.
Set the Text property to "Input". Set the Checkable property to false. Set the ToolTip property to "Input controls".
8. With the "Input" node selected, click the "Add child item" button four times to add four child nodes.
On the first, set the Text property to "RadTextBox" and the ImageUrl property to "~/Images/RadTextBox.png". On the second, set the Text property to "RadMaskedTextBox" and the ImageUrl property to "~/Images/RadTextBox.png". On the third, set the Text property to "RadNumericTextBox" and the ImageUrl property to "~/Images/RadTextBox.png".
430
On the fourth, set the Text property to "RadDateInput" and the ImageUrl property to "~/Images/RadTextBox.png".
9. Click OK to exit the Item Builder. 10. Using the Properties Window, set the CheckBoxes and SingleExpandPath properties to true.
Set the DataTextField property to "LastName". Set the DataFieldID property to "EmployeeID". Set the DataFieldParentID property to "ReportsTo".
Smart Tag
The RadTreeView Smart Tag looks like the typical Smart Tag of a RadControl that contains items which can be either statically declared or loaded from a data source:
431
At the top of the Smart Tag, the Choose Data Source drop-down to bind the tree view and the Build RadTreeView link to bring up the Item Builder should be familiar by now. So should the standard Ajax Resources, Skin Selection, and Learning Center items. Because you can define item templates for the tree view, there is also an Edit Templates link to bring up the Template Design Surface. If you bind the tree view to a data source, the Smart Tag changes to its bound version:
The bound Smart Tag lets you change the data source, reconfigure the current data source, or refresh the schema. In addition, there is a link to bring up the NavigationItemBinding Collection Editor. This collection should be familiar to you from the Data Binding chapter. The bound Smart Tag still contains the Edit Templates item to bring up the Template Design Surface.
Properties Window
At design time, you can use the Properties Window to configure almost every aspect of the tree view, with the exception of templates. As before, let us look at the most important properties.
Specifying Items
Probably the most important property of the tree view is the one that specifies what items appear and their hierarchical relationships. What properties you choose for this task depends on whether you want to load items from a data source:
If you want to load items from a data source, you can use the the standard data-binding properties
432
If you want to establish a hierarchical relationship between nodes, use the DataFieldID and DataFieldParentID properties. When setting up a hierarchy in this way, you can use the MaxDataBindDepth property to limit the depth of the hierarchy. When using an inherently hierarchical data source such as an XmlDataSource or SiteMapDataSource, there is no need to use the DataFieldID and DataFieldParentID properties. The hierarchy is automatically honored by the tree view.
If you want to use statically declared items, you can use the Nodes property to bring up the RadTreeView Item Builder, or you can switch to the Source view and define the structure directly in the mark-up. If you want to use both data-bound and statically-declared items, set the AppendDataBoundItems property to true.
The AllowNodeEditing property makes nodes editable. When AllowNodeEditing is true, users can edit the text of nodes by clicking on a node a second time once it is selected (the same way you can edit the item text in RadControl Item Builder dialogs). The CheckBoxes property adds check boxes to the nodes. The check boxes feature is described in more detail later in this chapter. The EnableDragAndDrop property allows the user to drag nodes and drop them on other nodes, or on other elements of the Web page. The drag-and-drop feature is also described in more detail later. The ContextMenus property lets you bring up the RadTreeViewContextMenus Collection Editor, where you can define the context menus that are used by items.
433
Each node has its own set of properties: Text is the string that represents the node, ToolTip is the tool tip for the node, and Value is a value associated with the node. You can add images to a node by setting the ImageUrl, DisabledImageUrl, ExpandedImageUrl, HoveredImageUrl and SelectedImageUrl properties. If any of the other image properties is not set, the node uses the ImageUrl property as the image default. You may also want to use the Selected, Enabled, and Expanded properties to specify the state of the item when the Web page first loads. The NavigateUrl and Target properties let you use the node to navigate to another Web page. A few properties determine whether the node participates in specific features that are enabled at the tree view level:
The AllowEdit property controls whether the node can be edited when the tree view's AllowNodeEditing property is true. The Checkable property controls whether the node gets a check box when the tree view's CheckBoxes property is true. The Checked property specifies whether the check box is checked when the page first loads. The AllowDrag and AllowDrop properties specify how the node participates in the drag-and-drop feature when the tree view's EnableDragAndDrop property is true. The EnableContextMenu property specifies whether the node displays a context menu when the user right clicks and the ContextMenus property collection defines a set of context menus. ContextMenuID specifies which context menu to use.
Collection Editors
434
When using the RadTreeViewContextMenu Collection Editor, the order of items does not matter, because each node is associated with a context menu by its ContextMenuID property. To make this work, you must take note of the ID property of each context menu in the collection, as this is the string that should be assigned to the ContextMenuID property. Another important property is the Items property, which can be used to bring up the RadContextMenu Item Builder, where you can define the items in the context menu. You may also wish to set the Skin property for the menu, as this is not inherited from the tree view.
435
When a tree view includes both a RadTreeNode template and individual item templates, the item templates have priority over the RadTreeNode template. That is, the RadTreeNode template is used for every node that does not have its own item template.
By default, all check boxes behave independently. However, in some applications, you may want to implement a cascading effect. That is, when a parent node is checked, all of its children are automatically checked as well, and when a parent node is unchecked, all of its children inherit that state. Achieving this effect is simple: just set the CheckChildNodes property to true. You can convert the check boxes in the tree view from ordinary two-state check boxes to tri-state check boxes by setting the TriStateCheckBoxes property to true. Tri-state check boxes have three states: "Checked", "Unchecked", and "Indeterminate". The state of a tri-state check box is intended to reflect the state of the check boxes on child nodes. When all the child nodes of a tri-state check box are checked, the tri-state check box is checked. When they are all unchecked, the tri-state check box is unchecked. When the child nodes are a mix of checked and unchecked nodes, the tri-state check box is in an indeterminate state. Changing the checked state of a child node automatically changes the state of all parent tri-state check boxes. Because of the relationship between the child nodes and parent nodes,set the CheckChildNodes property to true when using tri-state check boxes. Otherwise, changing the checked state of parent nodes does not make much sense. After a postback, the state will always revert to one that reflects the checked state of child nodes. The following walk-through explores some of the features of RadTreeView check boxes. It creates a Web page with two tree views on it, one with ordinary check boxes, and one with tri-state check boxes. Both have the CheckChildNodes property set to true so that child nodes are updated when the parent node is checked. In addition, an event handler automatically expands or contracts the child nodes of a node when its check box is
436
You can find the complete source for this project at: \VS Projects\TreeView\CheckBoxes
437
438
439
Drag-and-Drop
To enable the drag-and-drop feature, set the EnableDragAndDrop property of the tree view control to true. When drag-and-drop is enabled, the user can drag any node that has its AllowDrag property set to true and drop it on any node that has its AllowDrop property set to true. The node can also be dropped on any element on the page that has its id attribute set, including the nodes of other tree views, as long as the other tree view has EnableDragAndDrop set to true and the node has AllowDrop set to true. If the MultipleSelect property of the tree view is set to true, the user can drag multiple nodes at a time. By default, when the user drops a node onto a tree view, it can only be dropped on another node. If you want to let the user drop a node between two other nodes, set the EnableDragAndDropBetweenNodes property to true. When EnableDragAndDropBetweenNodes is true and the user drags a node between two nodes on the tree view, the tree view displays a line where the node will land if dropped. When the user drops a node (or nodes) on a valid drop location (a node with AllowDrop set to true or an element with an id attribute), the server-side NodeDrop event handler is called. This is where you must handle the drop event, implementing whatever changes the action implies. The following example illustrates how to implement drag-and-drop. It contains a tree view control with dragand-drop enabled and an ASP.NET panel. When the user drags a node from one position in the tree view to another, the node is removed from its old position and added to the new one. When the user drags a node from the tree view to the panel, a label inside the panel is updated to indicate where the node came from.
You can find the complete source for this project at: \VS Projects\TreeView\DragAndDrop
440
To enable drag-and-drop, the tree view has EnableDragAndDrop set to true. It also has EnableDragAndDropBetweenNodes set to true, to allow nodes to be dragged between other nodes, as shown in the screen shot above. The NodeDrop event occurs when a drag operation ends on a valid target: [VB] NodeDrop event handler Protected Sub RadTreeView1_NodeDrop(ByVal sender As Object, _ ByVal e As RadTreeNodeDragDropEventArgs) _ Handles RadTreeView1.NodeDrop Dim sourceNode As RadTreeNode = e.SourceDragNode Dim destNode As RadTreeNode = e.DestDragNode ' don't allow a node to be dropped on itself If sourceNode.Equals(destNode) Then Return End If ' destNode is set if dropping on another node of the tree If Not destNode Is Nothing Then ' remove the node from its current parent sourceNode.Owner.Nodes.Remove(sourceNode) If destNode.Level = 0 Then ' dropping on a group node ' insert in the first position destNode.Nodes.Insert(0, sourceNode) Else ' dropping on a leaf node Select Case e.DropPosition Case RadTreeViewDropPosition.Over, RadTreeViewDropPosition.Below ' add after destNode.InsertAfter(sourceNode) Exit Select Case RadTreeViewDropPosition.Above ' add before destNode.InsertBefore(sourceNode) Exit Select End Select End If ElseIf e.HtmlElementID = "Panel1" Then ' node was dropped on the panel If Label1.Text <> "" Then Label1.Text += "<br>" Label1.Text += String.Format("{0} is in {1}", sourceNode.Text, sourceNode.ParentNode.Text) End If End Sub [C#] NodeDrop event handler protected void RadTreeView1_NodeDrop(object sender, RadTreeNodeDragDropEventArgs e) { RadTreeNode sourceNode = e.SourceDragNode; RadTreeNode destNode = e.DestDragNode; // don't allow a node to be dropped on itself if (sourceNode.Equals(destNode)) return; // destNode is set if dropping on another node of the tree
441
442
Context Menus
To add context menus to the nodes of the tree view, you must first add the context menus to the ContextMenus property collection of the tree view. Then, assign the ContextMenuID property of each node to the ID of the desired context menu. Use the EnableContextMenu property of each node to enable or disable context menus for that item. Gotcha! You must add the context menus to the ContextMenus property collection. Adding a separate RadContextMenu control to the page and setting the ContextMenuID property of a tree view node to its ID does not work. When the user clicks on an item in the context menu, you can implement the response by using the server-side ContextMenuItemClick event, or by using the client-side OnClientContextMenuItemClicking or OnClientContextMenuItemClicked event.
443
You can find the complete source for this project at: \VS Projects\TreeView\ContextMenus The tree view includes the definitions of the two context menus in its ContextMenus property collection. Each node sets its ContextMenuID property to the ID of the context menu it uses: [ASP.NET] Tree view with context menus <telerik:RadTreeView ID="RadTreeView1" Runat="server" Skin="Sunset" oncontextmenuitemclick="RadTreeView1_ContextMenuItemClick" OnClientContextMenuItemClicking="HandleInternalNodeContextMenu" > <ContextMenus> <telerik:RadTreeViewContextMenu ID="LeafMenu" runat="server" Skin="Sunset"> <Items> <telerik:RadMenuItem runat="server" Text="Move up" /> <telerik:RadMenuItem runat="server" Text="Move down" /> <telerik:RadMenuItem runat="server" Text="Delete" /> </Items> </telerik:RadTreeViewContextMenu> <telerik:RadTreeViewContextMenu ID="InternalNodeMenu" runat="server" Skin="Sunset"> <Items> <telerik:RadMenuItem runat="server" Text="Reset nodes" /> </Items> </telerik:RadTreeViewContextMenu> </ContextMenus> <Nodes> <telerik:RadTreeNode runat="server" Text="Languages" Expanded="true" ContextMenuID="InternalNodeMenu" > <Nodes> <telerik:RadTreeNode runat="server" Text="English" ContextMenuID="LeafMenu" > </telerik:RadTreeNode> ... </Nodes> </telerik:RadTreeNode> ... </Nodes> </telerik:RadTreeView>
444
445
446
You can find the complete source for this project at: \VS Projects\TreeView\ServerSide The button's Click handler starts out by collapsing all nodes in the tree view, so that in the end, only the path of the specified node will be open. Then it locates the node that matches the text in the text box and selects it. Next the Click handler traverses the node hierarchy from the specified node, first upwards, to expand all ancestor nodes, and then downwards, to expand all descendants. [VB] Expanding nodes upward and downward Private Sub ExpandAllChildren(ByVal node As RadTreeNode)
447
448
The SELECT statement of your data source can flatten all of the tables into a single table, using one or more JOIN or UNION clauses. You can build the tree view node hierarchy in the Page_Load event handler.
The following example illustrates the latter approach. In the Page_Load event handler, it builds the node hierarchy of a tree view from three separate data tables ("Regions", "Territories", and "Employees").
449
You can find the complete source for this project at: \VS Projects\TreeView\ServerRelatedTables The Page_Load event handler only needs to generate the node hierarchy the first time the page loads: [VB] Page_Load event handler Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load ' we only need to generate the table when the page first loads If Not IsPostBack Then GenerateTreeView() End If End Sub [C#] Page_Load event handler protected void Page_Load(object sender, EventArgs e) { // we only need to generate the table when the page first loads if (!IsPostBack) GenerateTreeView(); } The code to generate the node hierarchy first creates a data set with the three related tables. It then traverses each table in the data set, building the node hierarchy as it goes. For descendant nodes, the data table is accessed using a Relation, so that only the nodes that should descend from the parent node are traversed. [VB] Building the node hierarchy
450
451
452
Server-side events
RadTreeView supports a wealth of server-side events for responding in the code-behind when the user interacts with the tree view. You have already seen some of these: The NodeCheck event that occurs when the user changes the state of a check box on a node, the NodeDrop event that occurs when the user drops a dragged node, and the ContextMenuItemClick event that occurs when the user selects an item in the context menu of a node.
NodeClick
One of the most useful server-side events is the NodeClick event, which fires when the user clicks on a node. Gotcha! When using the NodeClick event, do not assign a value to the node's NavigateUrl property. When NavigateUrl is set, clicking on a node causes a different page to be loaded in the same or another browser window. The page redirection means that the NodeClick event will not fire. The following example illustrates one use of the NodeClick event. The Web page contains a tree view control and a PlaceHolder. When the user clicks on a leaf node of the tree view, the associated text is fetched from the server and added to the PlaceHolder.
You can find the complete source for this project at: \VS Projects\TreeView\ServerNodeClick When the NodeClick event handler is assigned, all nodes automatically trigger a postback when the user clicks on them. To prevent the postback from occurring on internal nodes, the PostBack property for those nodes is set to false. [ASP.NET] Suppressing the postback on internal nodes <telerik:RadTreeView ID="RadTreeView1" runat="server" Skin="Office2007" OnNodeClick="RadTreeView1_NodeClick" > <Nodes> <telerik:RadTreeNode runat="server" Text="Nursery Rhymes" ExpandedImageUrl="~/Images/FolderOpen.gif" ImageUrl="~/Images/folder.gif" PostBack="False" > <Nodes> <telerik:RadTreeNode runat="server" Text="Jack and Jill" /> <telerik:RadTreeNode runat="server" Text="Little Bo-Peep" /> <telerik:RadTreeNode runat="server" Text="Little Jack Horner" /> </Nodes> </telerik:RadTreeNode> <telerik:RadTreeNode runat="server" Text="Random"
453
454
NodeEdit
When node editing is enabled (the AllowNodeEditing property is true), the tree view automatically permits the user to edit the Text propertyof nodes. This is true even if you use an item template (in that case, when the user finishes editing the text, any controls in the template that are bound to the item's Text or the field specified by DataTextField are automatically updated.) Unfortunately, any changes that the user makes by editing nodes do not persist after a postback. To allow the edits to persist, you must handle the NodeEdit event. The following walk-through illustrates this issue. You can find the complete source for this project at: \VS Projects\TreeView\ServerNodeEdit 1. Create a new ASP.NET Web Application and drag a ScriptManager from the Tool Box onto the Web page. 2. Drag a Button from the Tool Box onto the Web page. Set its Text property to "Postback".
455
9. Click the "Postback" button. After the postback, all the nodes revert to their old Text values!
10. To allow the new text values to persist, add the following NodeEdit event handler: [VB] NodeEdit event handler Protected Sub RadTreeView1_NodeEdit(ByVal sender As Object, _ ByVal e As RadTreeNodeEditEventArgs) _ Handles RadTreeView1.NodeEdit ' Assign the Text property of the node ' so that the new value persists e.Node.Text = e.Text End Sub [C#] NodeEdit event handler protected void RadTreeView1_NodeEdit(object sender, RadTreeNodeEditEventArgs e) { // Assign the Text property of the node // so that the new value persists e.Node.Text = e.Text; } 11. Before trying out this change, add a RadAjaxManager to the Web page, and configure it so that postbacks initiated by the tree view cause the tree view to update. 12. Press Ctrl-F5 again. This time, if you edit the Text of some nodes and hit the "Postback" button, the change persists. Another good use of the NodeEdit event is to save the user's edits back to a database or other permanent storage.
456
The expand() and collapse() methods let you change whether the node is expanded. (You can also use the toggle() method to change the node's state from one to the other.) The select() and unselect() methods let you change whether the node is selected. The check() and uncheck() methods let you change the checked state of a check box on the node. The startEdit() and endEdit() methods let you switch the node in and out of edit mode. The highlight() and unhighlight() methods let you change whether the node is highlighted.
Another useful method is the scrollIntoView() method, which scrolls the tree view so that the node becomes visible. The scrollIntoView() method scrolls the tree view so that the node's current position is in view. However, this method does not expand any of the node's parent nodes. If one of the parent nodes is not expanded, the node will still not be visible, even after a call to scrollIntoView(). The following example illustrates a number of the methods of the client-side RadTreeNode object. The Web page has a RadTextBox and a RadTreeView on it. When the user enters a string in the text box and clicks its button, the tree view expands all parents of the matching node, selects it, and scrolls it into view.
You can find the complete source for this project at: \VS Projects\TreeView\ClientSide The text box's OnButtonClick client-side event handler first locates the matching node by calling the tree
457
458
459
You can find the complete source for this project at: \VS Projects\TreeView\ClientTreeView The tree view has an OnClientLoad event handler which accesses the DOM element for the tree view and attaches a handler to its onfocus event. It also saves a reference to the tree view object in a global variable, so that there is no need for a call to the Sys.Application.findComponent() method ($find()) every time the application needs to call one of the tree view methods. [JavaScript] Attaching a handler to the onfocus event of the DOM object var tree; function OnLoad(sender) { // save a reference to the tree view for later tree = sender; // add the event handler to the onfocus event of the tree view var treeDiv = sender.get_element(); treeDiv.onfocus = function() { FindNode(); }; } Before looking at the FindNode function, which handles the onfocus event of the tree view, let use first look at two helper functions that illustrate the difference between the results fromthe get_nodes() method and the get_allNodes() method. The get_nodes() method returns a tree node collection object.Toiterate through all the nodes in this collection, use its getNode() method to access nodes and its get_count() method to get the number of nodes. (The node collection also has methods for inserting and removing nodes, which we are not using here.) [JavaScript] Iterating nodes returned by get_nodes() function ExpandRootNodes() { // get the nodes collection var rootNodes = tree.get_nodes(); var index; // iterate the nodes collection, expanding every node
460
In addition to using the findNodeByText() method to match the text of a node, it also calls the findNodeByAttribute() method to look for a match to the "CommonName" or "AltName" custom attributes. It calls the ExpandRootNodes() function shown above to expand the root nodes if no match is found. It calls the CollapseAllNodes() function shown above before opening a path to the matching node so that any other nodes in the tree view are collapsed. It does not call the scrollIntoView() method, but rather, just lets the tree view grow to accommodate its contents.
[JavaScript] Locating a node by text and custom attribute function FindNode() { // get a reference to the text box var textBox = $find("<%= RadTextBox1.ClientID %>"); // if no text specified, just expand the root nodes if (textBox.get_value() == "") ExpandRootNodes(tree); else { // locate the node var node = tree.findNodeByText(textBox.get_value()); // if the entered string was not the text of a node, // try the CommonName attribute if (node == null) node = tree.findNodeByAttribute("CommonName", textBox.get_value()); // if the common name was not found either, try the AltName attribute if (node == null) node = tree.findNodeByAttribute("AltName", textBox.get_value()); if (node != null) { // collapse the tree CollapseAllNodes(tree);
461
If there is only a single root node, it is impossible to use because the scroll bar obscures the expand button. 6. Close the running application, and switch to the Source view of your Web page. 7. Locate the tag for the root node with the long text values and add the style="white-space: normal;" attribute to the node. [ASP.NET] Long tree node with style attribute <telerik:RadTreeNode runat="server" style="white-space: normal;" Text="The root node of this tree view has a very, very, long text value."> <Nodes> ... </Nodes> </telerik:RadTreeNode> 8. Press CTRL-F5 to run the application again. This time, the text of the root node wraps to fit in the allotted width.
462
You can also add the style="white-space: normal;" to the <telerik:RadTreeView> tag to enable wrapping for all of the nodes in the tree view. You can find the complete source for this project at: \VS Projects\TreeView\HowToWrappingNodeText
You can find the complete source for this project at: \VS Projects\TreeView\HowToControlsCollection The color picker is added in the Page_Load event handler: [VB] Adding controls to a node Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load ' Go through all of the nodes in the tree view
463
16.9 Performance
RadTreeView supports a large number of nodes, but it can only show a limited number of nodes at a time on the client side. As the number of nodes increases, the size of the HTML file that clients must download can become significant. Not only must the tree view itself be downloaded, but the View State for state management and JavaScript that implements the behavior adds to the size of the Web page. If a tree contains more than about 200 nodes, it is not practical to load the entire tree at once. To manage the size of downloads and improve performance, you can configure the tree view to load nodes only when they are needed. Similar to the load-on-demand mechanism you have already seen with RadComboBox, you can load tree view nodes on demand from either a server-side event handler or a Web service.
Load on demand
The tree view load-on-demand mechanism is designed to work on a node by node basis. That is, you can use load-on-demand to expand some nodes, while allowing others to be expanded on the client as in a smaller tree
464
ClientSide (the default): nodes are not loaded on demand, but rather, they are downloaded with the Web page. ServerSide: When the user expands the node, it generates a postback and the NodeExpand event handler is called to supply child nodes. ServerSideCallBack: This is the same as ServerSide, except that the tree view generates an AJAX callback rather than a postback. While waiting for the results of the callback, the string specified by the tree view's LoadingMessage property is displayed in the position specified by the LoadingStatusPosition property. WebService: When the user expands the node, it generates a callback to the Web Service (and Web Method) specified by the WebServiceSettings property.
The following example illustrates four different expand modes. It contains a tree view that starts with four nodes, a root node and three child nodes. The root node has its ExpandMode property set to "ClientSide"; the first child node has its ExpandMode property set to "ServerSide"; the second child node has its ExpandMode property set to "ServerSideCallBack"; the third child node has its ExpandMode property set to "WebService". When the user expands a node, the NodeExpand callback or WebService method adds 10 child nodes, each with the same expand mode as the node that is expanding.
You can find the complete source for this project at: \VS Projects\TreeView\LoadOnDemand
465
The NodeExpand event handler is called to add the children of nodes with ExpandMode set to "ServerSide" or "ServerSideCallBack". [VB] Adding child nodes using a NodeExpand callback Protected Sub RadTreeView1_NodeExpand(ByVal sender As Object, _ ByVal e As Telerik.Web.UI.RadTreeNodeEventArgs) _ Handles RadTreeView1.NodeExpand Dim i As Integer = 1 While i <= 10 ' get the naming index Dim nameIndex As String = e.Node.Value If nameIndex <> "" Then nameIndex += "." End If nameIndex += i.ToString() ' create a new node Dim newNode As New RadTreeNode("Child " + nameIndex) ' set the Value to the nameIndex newNode.Value = nameIndex ' with the same expand mode as the node currently expanding newNode.ExpandMode = e.Node.ExpandMode ' add the new node to the node that is expanding e.Node.Nodes.Add(newNode) System.Math.Max(System.Threading.Interlocked.Increment(i),i - 1) End While ' now that the nodes are added, change the current node's expand mode to client-side e.Node.ExpandMode = TreeNodeExpandMode.ClientSide ' signal that the node is now expanded e.Node.Expanded = True End Sub [C#] Adding child nodes using a NodeExpand callback protected void RadTreeView1_NodeExpand(object sender, Telerik.Web.UI.RadTreeNodeEventArgs e) { for (int i = 1; i <= 10; i++) { // get the naming index string nameIndex = e.Node.Value; if (nameIndex != "") nameIndex += "."; nameIndex += i.ToString(); // create a new node RadTreeNode newNode = new RadTreeNode("Child " + nameIndex); // set the Value to the nameIndex newNode.Value = nameIndex; // with the same expand mode as the node currently expanding newNode.ExpandMode = e.Node.ExpandMode; // add the new node to the node that is expanding e.Node.Nodes.Add(newNode); } // now that the nodes are added, change the current node's expand mode to client-side e.Node.ExpandMode = TreeNodeExpandMode.ClientSide;
466
467
Instead of an event arguments object that provides access to the RadTreeNode object for the expanding node, the Web Method has a RadTreeNodeData argument, which supplies information about the node properties. Instead of adding new nodes directly into the Nodes property collection of the expanding node, the Web Method returns an array of RadTreeNodeData objects for the nodes that need to be added. Note the second parameter of the Web Method. This is a context object (of type IDictionary) that can supply context information supplied by a client-side OnClientNodeExpanding event handler. This context object works the same way as the context object used with the RadComboBox load-on-demand feature.
16.10Summary
In this chapter you looked at the RadTreeView control and saw how you could add the functionality of a desktop tree view to your Web applications. You created a simple application that populated one tree view with statically declared items and another with items loaded from a data source. At the same time, you looked at some properties of the tree view and tree nodes. You looked at the design time support for the tree view andsaw many of the properties and groups of properties you can use to configure the tree view and its nodes at design time. You learned about the special features of RadTreeView, including node editing, check boxes, drag-and-drop, and node context menus. You learned some of the server-side properties and methods, and explored how to propagate a change to all of the ancestors or descendants of a node. You learned to build the node hierarchy dynamically in server-side code, and saw how this could be used to populate a tree view with data from multiple tables. You also learned about several of the tree view server-side events. You explored some of the client-side methods for working with the tree node and tree view objects. You learned how to implement the 'radio button' pattern for state changes on nodes, and saw how to attach an event handler directly to the tree view's DOM object when the tree view first loads. You learned a few "tricks" for working with the tree view, such as getting the text of nodes to wrap and how to add controls directly to tree nodes without using templates.
468
469
17.1 Objectives
Explore features of the FileExplorer control. Learn how to configure RadFileExplorer using Property window in Visual Studio. Learn how to configure RadFileExplorer on the server. Learn how tolocalize RadFileExplorer. Learn some advance customizations: create and register a custom FileBrowserContentProvider. Learn how to control RadFileExplorers content using its client-side API.
17.2 Introduction
RadFileExplorer was officially included in the Q1 2009 release of RadControls for ASP.NET AJAX. It allows you to easily add file explorer functionality to your pages providing the users an ability to organize files and folders on the server through web interface.
Main features:
A single control, integrated in Telerik.Web.UI - ready to drag and drop on the page Load on demand approach to load its content using ASP.NET AJAX Callback mechanism Uses a ContentProvider model which introduces an abstraction of the underlying datasource. This allows the control to be connected to any kind of datasource like OS filesystem, database, MOSS SharePoint, Amazon S3, Windows Azure, etc. Supports files and folders sorting Ability to delete and rename files and folders, create new folders, etc. Client and server side events for file operations like delete, create new folder, etc. Context menu commands for common operations
470
Designer Interface
471
Smart tags
The RadFileExplorer Smart Tag contains only the common elements of RadControls Smart Tags: the Ajax Resources, Skin selection, and Learning center:
Property window
At design time, you can use the configuration window to configure almost every aspect of RadFileExplorer. Probably the most important properties of RadFileExplorer are combined in a group called Configuration.
ViewPaths accepts an arrayof folder pathsthat will be listed in the RadFileExplorer UploadPaths / DeletePaths accepts an arrayof folder pathswhere the user should have Upload / Delete permissions. If you wish to restrict Upload and Delete you can simply do not provide value to these properties. SearchPatterns - this property is used in order to filter the files displayed in RadFileExplorer. The values set to this property may contain wildcards. The default value of the property is *.*. which means All files MaxUploadFileSize - sets limit of the uploaded files. ContentProviderTypeName - sets the qualified assembly name of the custom content provider which will
472
In the property window you can assign RadFileExplorer's client-side event handlers:
OnClientCreateNewFolder is fired when the user creates a new folder. OnClientDelete is fired when the user deletes file or folder. OnClientFileOpen is fired when the user opens a file for preview (this feature have to be enabled setting the EnableFileOpen=true property) OnClientFolderChange is fired when the user selects a folder from the TreeView OnClientFolderLoaded is fired when the folders content is fully loaded OnClientItemSelected is fired when the user selects a file item (not a folder) OnClientLoad is fired when the RadFileExplorer control is fully loaded OnClientMove is fired when the client tries to move or rename a file and /or folder.
EnableOpenFile - If the value is true, by default when a file is double clicked it will be opened in a RadWindow dialog for preview. This default behavior can be easily overridden, however, in order to cover more specific scenarios. For example, if the implemented scenario requires the file to be opened in a different dialog than the default one. EnableCopy - enables or disables copy feature of the control AllowPaging - enables paging on the Grid. This property can be combined with the PageSize property. EnableCreateNewFolder - allows or restricts creating a new folder. VisibleControls - controls which of the of RadFileExplorer elements (Grid, TreeView, etc.) to be visible. You can provide multiple values to this property by separating them with commas (,) in the markup or using bitwise OR (|) on the server. ExplorerMode - accepts two enum values:
Default - the default mode of the control FileTree - In this mode the Grid part of the control will be disabled and the files will be displayed in the TreeView.
473
TreeView - returns reference to the RadTreeView embedded in RadFileExplorer GridContextMenu - returns reference to the context menu shown over the grid's items ToolBar - returns reference to the radToolBar control ToolTip - returns reference to the RadToolBarControl WidnowManager - returns reference to the RadWindowManager control embedded in RadFileExplorer Splitter - returns reference to the RadSplitter control embedded in RadFileExplorer
Server-Side events
ItemCommand
This event is called when Deleting, Uploading, Creating, Moving (move and rename are the same operations)a file/folder. The event can be canceled by setting Cancel=true property of the passed argument to the ItemCommand event C# protected void RadFileExplorer1_ItemCommand(object sender, RadFileExplorerEventArgs e) { switch (e.Command) { case "UploadFile": break; case "MoveDirectory": break; case "CreateDirectory": break; case "DeleteDirectory": break; case "DeleteFile": break; case "MoveFile": break; } // e.Cancel = true; // Cancel the operation } VB.NET Protected Sub RadFileExplorer1_ItemCommand(ByVal sender As Object, ByVal e As RadFileExplorerEventArgs) Select Case e.Command Case "UploadFile" Exit Select Case "MoveDirectory" Exit Select Case "CreateDirectory" Exit Select Case "DeleteDirectory" Exit Select Case "DeleteFile" Exit Select Case "MoveFile" Exit Select ' e.Cancel = true // Cancel the operation End Select End Sub
474
475
476
If you do not provide any of parameters a dialog will pop-up asking for name of the folder and will create it as a sub-folder to the currently selected one If the function is called passing the path parameter, then the folder will be created to that path. A dialog will pop-up asking for name of the folder. If both of parameters are passed then the folder will be created without showing any pop-up dialog
When the createNewDirectoryis called, the CreateDirectory method of the FileBrowserContentProvider will be called on the server, if the event is not canceled in RadFileExplorers ItemCommand server-side event All client-side objects of the RadFileExplorer component (grid, TreeVIew, etc.) are exposed as properties and can be used to modify the default behavior of the control. For example, this JavaScript code shows how to get reference to the RadGrids client object: JavaScript var gridObject = radFileExplorer.get_grid();
17.6 How To
Set configurationproperties incodebehind The Configuration properties can be set using server-side code as well. This is an example setup: C# protected void Page_Load(object sender, EventArgs e) { // ROOT folder's content will be visible, including CanUploadDirectory and CanDeleteDirectory directories string[] viewPaths = new string[] { "~/ROOT" }; // Allows upload TO ~/ROOT/CanUploadDirectory // Delete is not allowed, so a file/folder cannot be moved FROM this folder // Allows copy TO this folder as well (if EnableCopy="true" is set) string[] uploadPaths = new string[] { "~/ROOT/CanUploadDirectory" }; // Allows Delete FROM ~/ROOT/CanDeleteDirectory // A folder/file can be moved FROM this directory as well // Upload, copy or move TO this folder is not allowed string[] deletePaths = new string[] { "~/ROOT/CanDeleteDirectory" }; RadFileExplorer1.Configuration.ViewPaths = viewPaths; RadFileExplorer1.Configuration.UploadPaths = uploadPaths; RadFileExplorer1.Configuration.DeletePaths = deletePaths; // Only .jpg and .gif files will be shown string[] searchPaterns = new string[] { "*.jpg", "*.gif" }; RadFileExplorer1.Configuration.SearchPatterns = searchPaterns; // Sets the max allowed size of the uploaded files
477
478
and edit the strings inside. For example theLanguage="de-DE" property forces the RadEditor.Dialogs.de-DE.resx file to be used by the RadFileExplorer control: Example Title <telerik:RadFileExplorer runat="server" ID="RadFileExplorer1" Width="575" Height="375" Language="de-DE" > <Configuration ViewPaths="~/ROOT/" DeletePaths="~/ROOT/" UploadPaths="~/ROOT/" /> </telerik:RadFileExplorer> Implementing a custom provider
RadFileExplorer loads its data through a content provider. This approach frees the developers to implement their own provider which can be used in order to connect RadFileExplorer to any kind of data sources (FTP filesystem, Database, etc.). Base class for all content providers is Telerik.Web.UI.Widgets.FileBrowserContentProvider. To implement a custom Content Provider you need to inherit that abstract class and implement its methods:
ResolveRootDirectoryAsTree Called in order to load all sub folders of the passed as parameter folder ResolveDirectory - called in order to load all child files of the passed as parameter folder StoreFile called in order to save an uploaded file DeleteFile called in order to delete a file DeleteDirectory - called in order to delete a directory CreateDirectory - called in order to create a directory CanCreateDirectory a readonly boolean property. This property allows explicitly restricting creating a new folder on the ContentProvider level. GetFile - used in two cases: 1) To identify if a file with the same name exists in the same path when uploading a file 2) When creating a thumbnail used to get the original image content StoreBitmap - used to save a newly created bitmap to the storage GetFileName - used to get the file name only from the given URL GetPath - used to get the directory path of an item (file or directory) from the given URL
479
get_text() - gets the text (keyword) to search for set_text(newText) - sets the text (keyword) to search for set_cancel(toCancel) - sets bool value that determines whether the filtering will be cancelled - set_cancel (true) will cancel the filtering process. get_domEvent() - gets a reference to the current domEvent - it comes handy when you need to determine which key was pressed
17.7 Summary
In this chapter you looked at the RadFileExplorer control and saw some of the powerful features it provides.
We exploredthe client-side and server-side properties of the control. Learned how toconfigure the controlserver-side or using Property window. You used the server-side events in order to sort theitems shown in the RadFileExplorer control or detect server-side activity. Learned how to change the localization of the control using .resx files. We explored the basic steps in order to use a custom Content Provider with the RadFileExplorer control.
480
18.1 Objectives
Explore the features of the RadSiteMap control. Create a simple application to get confidence in using the site map and to see how to bind to various types of data sources, including declarative data sources. Explore the site map design time interface, including Smart Tag, Properties Window, Property Builder, Collection Editors and Template Design surface. Explore principal properties and groups of properties where most of the functionality is found. Learn server-side coding techniques and handling server-side events
18.2 Introduction
With the ease of Teleriks SiteMap for ASP.NET AJAX you can organize and list the pages on your web site, customize the layout, choose from a variety of appearance options and templates. Add value to your web site by optimizing it for crawler and search engines with no extra development effort.
RadSiteMap combines the highly efficient rendering of RadControls for ASP.NET AJAX with a powerful set of features. You can use the familiar skinning capabilities to make the site map fit in with the look and feel of your Web site, as well adjusting the appearance using styles or item templates. The capabilities of RadSiteMap extend beyond simply changing the appearance. You can configure the layout of RadSiteMap in a variety of modes. The nodes can be viewed in either list or flow mode. By selecting the flow property items in the group will be arranged in rows one after the other, instead of displaying them as a list. You can also alternate between single, multi-column, horizontal or vertical view. In addition you can display node lines in a fashion similar to RadTreeView. The ASP.NET SiteMap by Telerik allows you to define a collection of dynamic templates that customize the presentation of the hierarchy and the individual nodes Following our long tradition of industry best cross-browser support, Telerik ASP.NET SiteMap doesnt make an exception. The component supports all major browsers, including Internet Explorer, Firefox, Safari, Opera and Google Chrome and produces identical results.
481
RadSiteMap completely follows the principles of Search Engine Optimization. The control renders semantic lists and standard anchor tags, which are properly recognized by search engines. As a result, all content accessible through this control will be automatically indexed and ranked with no extra effort required from the developer.
482
You can find the complete source for this project at: \VS Projects\SiteMap\GettingStarted Prepare the project 1. Create a new ASP.NET Web Application and drag a ScriptManager from the Tool Box onto the Web page. 2. Locate the "SiteMap.mdf" file and drag it into the "App_Data" folder of your project. 3. Open the "Web.config" file of your project. Add SiteMap connection string to your project by replacing the line <connectionStrings /> with: web.config <connectionStrings> <add name="SiteMapConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\SiteMap.mdf;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient" /> </connectionStrings>
483
Smart Tag
The RadSiteMap Smart Tag looks like the typical Smart Tag of a RadControl that contains items which can be either statically declared or loaded from a data source:
484
At the top of the Smart Tag, the drop-down to bind the site map and the link to bring up the Item Builder should be familiar by now. So should the standard Ajax Resources,Skin Selection, and Learning Center items. Because you can define item templates for the site map, there is also an Edit Templates link to bring up the Template Design Surface. If you bind the site map to a data source, the Smart Tag changes to its bound version: The bound Smart Tag lets you change the data source, reconfigure the current data source, or refresh the schema. In addition, there is a link Edit RadSiteMap Databindings to bring up the NavigationItemBinding Collection Editor. This collection should be familiar to you from the Data Binding chapter. The bound Smart Tag still contains the Edit Templates item to bring up the Template Design Surface. Properties Window At design time, you can use the Properties Window to configure almost every aspect of the site map, with the exception of templates. As before, let us look at the most important properties.
Specifying Items
Probably the most important property of the site map is the one that specifies what items appear and their hierarchical relationships. What properties you choose for this task depends on whether you want to load items from a data source:
If you want to load items from a data source, you can use the standard data-binding properties (DataSourceID and DataMember), or use the DataSource property and DataBind>method in the codebehind.
When binding RadSiteMap to a data source, you can use the DataTextField,DataValueFieldandDataNavigationUrlField propertiesto map fields from the data source to properties of the nodes, or use the DataBindingsproperty to map even more node properties.
If you want to establish a hierarchical relationship between nodes, use the DataFieldIDand DataFieldParentID properties. When setting up a hierarchy in this way, you can use the MaxDataBindDepthproperty to limit the depth of the hierarchy. When using an inherently hierarchical data source such as an XmlDataSource or SiteMapDataSourcethere is
485
If you want to use statically declared items, you can use the Nodes property to bring up theRadSiteMap Item Builder or you can switch to the Source view and define the structure directly in the mark-up. If you want to use both data-bound and statically-declared items, set theAppendDataBoundItemsproperty to true.
486
Each node has its own set of properties: Text is the string that represents the node, ToolTip is the tool tip for the node, and Value is a value associated with the node. You can add images to a node by setting the ImageUrl, DisabledImageUrl, HoveredImageUrl and SelectedImageUrl properties. If any of the other image properties is not set, the node uses the ImageUrl property as the image default. You may also want to use the Selected and Enabled properties to specify the state of the item when the Web page first loads. The NavigateUrl and Target properties let you use the node to navigate to another Web page.
Collection Editors
RadSiteMap uses two associated collection editors, the NavigationItemBinding Collection Editor which is used to edit the DataBindings property collection, and the LevelSettings Collection Editor, which is used to define the appearance of the nodes according to their level in the hierarchy. You have already seen how the NavigationItemBinding Collection Editor works in the Data Binding chapter. Let us look briefly at the LevelSettings Collection Editor
487
When using the LevelSettings Collection Editor, you can control the appearance of the associated Level in the RadSiteMap. With the Level property you can choose to which Level you will perform changes in appearance. When set to -1 the following changes will be made to all levels. The Layout property has two values: List and Table-Like. It controls the way the nodes are aligned. MaximumNodes property controls the number of nodes per parent level. When the number of nodes over reaches this property all the nodes over the value of MaximumNodes are moved to other column. SeparatorTextdetermines the character which will separate the nodes.
488
When a site map includes both a RadSiteMap template and individual item templates, the item templates have priority over the RadSiteMap template. That is, the RadSiteMap template is used for every node that does not have its own item template.
Server-Side events
RadSiteMap supports a number of server-side events for responding in the code-behind when the user interacts with the site map.
NodeDataBound
The NodeDataBound event fires for every Node that is bound to data. The following example illustrates the use of the NodeDataBound event. The Web Page contains a RadSiteMap binded to a SqlDataSource. When user hovers on a node of the site map tooltip appears referencing the text and the url of the node.
You can find the complete source for this project at: \VS Projects\SiteMap\ServerNodeDataBound From the Getting Started chapter you are already familiar how to bind the RadSiteMap to a declarative data sources such as SqlDataSource. The addition here is that we are subscribing to the NodeDataBound event of the RadSiteMap.
489
On the first siteMapNode, set only the title=Software and the description to "Telerik home page". On the second, set the url to http://www.microsoft.com/student/en/us/software/windows-7.aspx, title=Windows 7 and the description to "Windows 7". On the third, set the url to http://www.microsoft.com/student/en/us/software/visual-studio.aspx, title=Visual Studio and the description to "Visual Studio". On the fourth, set the url to http://www.microsoft.com/student/en/us/software/expressionstudio.aspx, title=Expression Studio and the description to "Expression Studio". On the fifth, set the url to http://www.microsoft.com/student/en/us/software/windowslive.aspx, title=Windows Live and the description to "Windows Live".
490
On the sixth, set the url to http://www.microsoft.com/student/en/us/software/office-2007.aspx, title=Microsoft Office and the description to "Microsoft Office".
In the RadSiteMap Smart Tag, select "<New data source...>" from the Choose Data Source drop-down. 6.
1. In the first page of the DataSource Configuration Wizard, select "SiteMap" as the application type, and click OK to move to the next page. 2. Right-click on the project in Solution Explorer Window and add new folder with name Images. Locate the 5 needed images for the project: windows7.png, visual_studio.png, expression.png, windowslive.png and office2010.png. 3. Add the following code lines to your RadSiteMap:
491
[ASP.NET]
<asp:Image ID="Image1" runat="server" Width="60px" Height="50px" CssClass="align"/> 1. Add this under the <title></title> tag: [CSS] <style type="text/css"> .align { vertical-align: middle; } </style>
492
You can find the complete source for this project at: \VS Projects\SiteMap\HowToSiteMapTemplates
18.7 Summary
In this chapter youve looked at the RadSiteMap control and saw how you could add an attractive site map to your Web applications. Youve created a simple application that populated one site map from a RadSiteMapDataSource and another with items loaded from a SqlDataSource. Youve explored the design time support for the site map and understood many of the properties and groups of properties you can use to configure the site map and its nodes at design time. Youve learned some of the server-side properties and methods, especially the NodeDataBound event. Finally, youve learned how to use Templates in a RadSiteMap. Youve built a simple application that used templates learned how to find controls in server code.
493
19.1 Objectives
Explore the features of the RadGrid control. Create a simple application that binds to some data to see the basic functionality of auto-generated columns and column manipulation. Explore theRadGrid design time interface, including Smart Tag, Properties View andProperty Builder. Enable and explain the principal properties and groups of properties where the most common functionality is found. Learn the most commonly used server-side API events and properties. Learn server-side coding techniques, including manual CRUD (create, read, update and delete) operations and accessing and changing the data in a grid by replacing values with images. Learn the client-side API with a comprehensive reference to all of the events, methods and properties of the RadGrid and GridTableView. Explore some advanced techniques in client-side code, such as client-side databinding and accessing values, changing appearance and binding to events with an example of client cell selection.
19.2 Introduction
In any web application where you need to display a list of data with more than one field, you are likely going to want to use a grid.The RadGrid is an advanced control with manybuilt in features that allow you toenable the most popular features of a grid with very little customization work. The RadGrid...
Allows you to enable fully functional multi-column sorting with a single setting. Sorting can be useful for arranging data in ways that are more useful to the user at any given time. Can enable a powerful filtering interface that can help in finding data without having to display all of it at the same time. Has an easily customizable paging feature that displays only small amounts of data at once to increase performance and decrease real estate usage while allowing access to a large number of records.
494
Can easily implement multilevel grouping of data from a single table - just drag the column header(s) to the group panel on the top, which defines the grouping order and hierarchy.You can also programmatically group the data using the group-by expressions.
Supports all widely used column types (GridEditCommandColumn, GridBoundColumn, GridCheckBoxColumn, GridDropDownColumn, GridButtonColumn, GridHyperLinkColumn, GridClientSelectColumn, etc.), columns with other Telerik controls as column editors (GridDateTimeColumn, GridNumericColumn, GridMaskedColumn, GridHTMLEditorColumn, etc.)as well as GridTemplateColumns, which give you complete freedom over the data layout and formatting. Can easily export the content to Microsoft Excel/Microsoft Word/CSV/PDF.
Auto-generated Columns
1. Start by creating a web application.
495
3. Drag it onto your design surface. Immediately, the RadGrids Smart Tag will open.
4. Configure the datasource to connect to the AdventureWorks database. 5. In the Configure the Select Statement step, select the "Specify a custom SQL statement" option and click Next. In the SELECT statement tab, enter the following query: [SQL] Vendor select statement SELECT * FROM Purchasing.[Vendor] 6. Click Next,test your query and click Finished. 7. You may recall that when the RadGrids Smart Tag was first presented, the "Auto-generate columns at runtime" option is checked by default.
496
Because we did so, the columns are automatically added to the RadGrid on our design surface. When the RadGrid is displayed once again, the columns will be captioned with the corresponding columns from the database table. Automatic column generation saves a lot of manual work by automatically matching the data types with the appropriate column types, such as checkboxes for boolean fields.
Manipulating Columns
1. Open the RadGrid's Smart Tag. 2. Click on the Open Property Builder link.
497
Lets consider the columns that are being displayed, and how we might present them differently: Vendor ID: This is a data key assigned automatically by the database, so it will never be editable. Furthermore, its primary function is to relate the vendor records to data in other tables, so although it has significance within the database, it has no intrinsic meaning to the end user. Set the Visible property to "false" to hide this column. CreditRating: This is a numeric score with a value between 1 and 5; so its pretty clear that the heading is forcing the column to be much wider than it needs to be. One way to solve this problem is to shorten the column header and provide a tooltip with the full "Credit Rating" description. Shorten the header by changing the HeaderText property found in the Appearance category to "CR". Similarly, shorten the headings for the columns "PreferredVendorStatus" to "Stat", and "ActiveFlag" to Act". Adding the tooltips takes a little bit of code: [VB] Adding tooltips to column headers Imports Telerik.Web.UI Protected Sub RadGrid1_ItemCreated(ByVal sender As Object, ByVal e As GridItemEventArgs) 'Check for GridHeaderItem if you wish tooltips only for the header cells If TypeOf e.Item Is GridHeaderItem Then Dim headerItem As GridHeaderItem = TryCast(e.Item, GridHeaderItem) headerItem("CreditRating").ToolTip = "CreditRating" headerItem("PreferredVendorStatus").ToolTip = "PreferredVendorStatus" headerItem("ActiveFlag").ToolTip = "ActiveFlag" End If End Sub [C#] Adding tooltips to column headers using Telerik.Web.UI;
498
You will also notice that the"ModifiedDate" column shows the date and time. Since the date portion is probably all you would care about in this context, let's take a look at how to set the format. 3. Close the web application and open the Property Builder again. 4. Select the Master Table | Columns | Modified Date entry to display the properties for the Modified Date column. 5. Locate the DataFormatString property in the Behavior section and enter the format string "{0:MM/dd/yyyy}" without the quote marks. The format string follows the Microsoft formatting conventions. The "0" at the beginning of the string indicates that the argument passed in to the formatter should be used as input. When you run the application, it will look something like this:
499
Clicking the ellipses will display the Grid Column Collection Editor. The same editor can be invoked by expanding the MasterTableView property for the RadGrid, and clicking the ellipses on the Columns property there:
This editor allows access to the same properties that youd find in the property builder. If youhave removed a column that you later find youd rather include in the display, you can add it back here. Start by clicking on the Add button. This will expand a list of different column types you can add to your grid:
GridBoundColumn: This will typically be used for unconstrained data; something other than a Boolean value or list-type data (which you would put in a GridDropDownColumn). GridCheckBoxColumn: Used for Boolean data. GridDropDownColumn: When the data entry choices are limited to items in a list, use this column type. When the column is in display mode, it will look just like a GridBoundColumn.You can also specify a data source, list text field, and list value field, so that in edit mode, the input is limited to the elements of the list. GridTemplateColumn: Theres a extensive discussion of templates included in the RadGrid documentation. When you create a template column, you have complete control over the contents of the template. You can include textboxes and images, set the background, control the arrangement and presentation of controls using tables, include labels; in short, theres a complete web page environment contained within each cell of the grid. GridEditCommandColumn: The EditCommandColumn enables editing of the data contained in the row. When you add a GridEditCommandColumn, the ButtonType property can be set to one of three types:
500
GridButtonColumn: A button column is very similar to the GridEditCommandColumn, except that you (not the designer) specify the name of the command that is sent to the web server for execution. GridHyperLinkColumn: As the name implies, this column has properties for the text and a URL to create a hypertext link. thereare also GridDateTimeColumn, GridMaskedColumn, GridNumericColumn, GridCalculatedColumn, GridClientSelectColumn, GridHTMLEditorColumn, GridImageColumn, GridBinaryImageColumn, GridRatingColumn, GridAttachmentColumn - you can find more information about the rest of the columnsin the Column Types help topic in the online documentation.
Hierarchical RadGrid
RadGrid gives you the ability to display hierarchical data through DetailTables or bydefining its NestedViewTemplate. Below are listed the different approaches you can use: DetailTables The RadGrid control renders one or more detail tables for each item (row) in the MasterTableView. In a multilevel hierarchy, each item of every detail table can have one or more detail tables as well. To describe the data hierarchy, each table view must have its own data source with ParentTableRelations or implementthe DetailTableDataBind event handler. In the next section you can see how to build hierarchical grid with detail tables through RadGrid designer. NestedViewTemplate With theNestedViewTemplateyou have the ability to model the look and feel of the child table container in order to display the detail info in non table-dependant format. In addition RadGrid exposes a property for its table view objects called NestedViewSettings. The NestedViewSettings allow you to specify a data source object contained on the page to which the template should be bound, as well as a relation to the parent level. These can be defined declaratively or programmatically through the NestedViewSettings.DataSourceID and NestedViewSettings.ParentTableRelation properties respectively. The ParentTableRelation is specified in the same way as the declarative relations for hierarchical tables. With the hierarchy declarative relations, you should have a WHERE clause in the SelectCommand of the data source control for the nested view template to retrieve the record for it. The WHERE clause should include the field from the ParentTableRelation definition between the master/child table. Furthermore, the same field has to be included in the SelectParameters of the "inner" data source controls with exactly the same Name. However, no SesssionField value is required. If more than one records are fetched from the data source for the nested view template, only the first one will be used to bind the controls in the latter. Below is a code extraction: ASPX <telerik:ScriptManager ID="ScriptManager1" runat="server" /> <telerik:RadAjaxManager ID="RadAjaxManager1" runat="server"> <AjaxSettings> <telerik:AjaxSetting AjaxControlID="RadGrid1"> <UpdatedControls> <telerik:AjaxUpdatedControl ControlID="RadGrid1" LoadingPanelID="RadAjaxLoadingPanel1" /> </UpdatedControls> </telerik:AjaxSetting> </AjaxSettings> </telerik:RadAjaxManager> <telerik:RadAjaxLoadingPanel ID="RadAjaxLoadingPanel1" runat="server" />
501
502
Enabling Ajax
When using the RadGrid, you will almost always want to use AJAX to prevent postbacks every time something in the RadGrid is changed. 1. If you do not already have a ScriptManager or RadScriptManager on your webpage, add a RadScriptManagerusing the RadGrid's Smart Tag. 2. In the Smart Tag there will be a link to register the RadScriptManager. Click that to register it in web.config. 3. Add a RadAjaxManager and configure it to have the RadGrid have an association withitself.
503
4. Now that the association is made, enable the RadGrid's ShowStatusBar property which will add an indicator to your grid that shows if it is loading or not.
There are three options to auto generate columns. By default, "Auto-generate columns at runtime" is turned on. The Auto-generate edit and delete column properties add ButtonColumns for deleting records and putting records into edit mode. The General Features area lets you turn on the commonly used Paging, Sorting, Filtering, Scrolling and Grouping features with their default options. Column Reordering can be enabled on the client or server side which allows you to drag columns around and change the order they appear in the grid.
504
It also provides useful links that allow you to easily Ajaxify the control and optimize the web page that the grid appears on.
Property Builder
You can open the Property Builder in the Smart Tag.
The Property Builder is a way of accessing almost every property available to the RadGrid in a more organized format than the Properties window. It is also good at displaying the current layout of columns, allowing easy access to column layout and properties.
505
Properties Window
If you know your way around the control, the Properties window can be a quicker way to manipulate the RadGrid and it is the only way to access and auto-create the server-side events in the CodeBehind from the Design Time Interface.
506
507
Paging
Paging allows you to limit the amount of data displayed at one time and provides controls to navigate pages of that limited data. This feature can be the single most important option for improving performance of a dataheavy web page. It also reduces the real estate usage and eliminatesclumsy horizontal scrollbars. To enable this feature, simply check the Enable Paging checkbox in the Smart Tag. The default setting for this feature includes showing 10 records at once and some basic navigation controls. There are many options to customize this behavior, accessible through the Property Builder:
Possible settings here include the number of rows per page and navigation button settings.If you enable paging and enable AJAX, then run the application, you'llnotice as you navigate the data thatthere are no postbacks. This slick performance is achievable with just a few mouse clicks.
Sorting
Sorting is a three-state functionality. When the contents of a sort-enabled grid are first displayed, they aresorted based on ordering from a SQL statement. When the Enable Sorting option is enabled, data is sorted by clicking on a column header. The first time the column header is clicked, the data will be sorted into ascending order, indicated by the triangular icon shown in the left-hand image below; the second time, it will be sorted in descending order, as shown in the right-hand image; and the third click will return the column to the original (grid-unsorted) order.
508
Filtering
Filtering is really used as a search and navigation tool.If you have paging enabled, the page navigation interface can take too much work to find specific data.Enabling filtering will allow your users to easily navigate to specific data quickly while keeping the performance advantage of paging. Enabling filtering is easily done by selecting the Enable Filtering property in the Smart Tag.
Special-type fields (such as dates and bit fields) have filter conditions conditions appropriate to the data type you're dealing with. The following screenshot shows the PreferredVendorStatus column showing only filter optionsthat would apply to a boolean value, while the Modified column shows filter options that would only apply to dates.
509
Column Grouping
The next property is the Enable Grouping property. When grouping is enabled, an extra area will be displayed at the top of the grid, indicating that you can drag a column header to the grouping area to group by that column. When your cursor is hovered over a groupable column, you'll first see a tooltip indicating that the column is groupable, and the cursor will change to a "Move" cursor:
To create a column grouping, simply left-click a column header and drag it into thegrouping header. As your cursor enters the grouping header, it will change back into an arrow, indicating that the group may be dropped and take effect. You can create multiple groupingsthat will be nested in the order that they appear in thegrouping header. This order may be changed by dragging the existing groupings around in the grouping header. You may sort groupings using the arrow icon next to each grouping and each group may be expanded or collapsed using the arrow icon next to each group value.
510
511
Scrolling
When scrolling is enabled using the Enable Scrolling checkbox in the Smart Tag, you'll see a vertical scrollbar along the right-hand edge of the grid. The Enable Scrolling checkbox setting has a convenient set of defaults. The other properties associated with the scrolling sub-property look like this:
The EnableVirtualScrolling property is especially useful if you're dealing with large data sets. What this property does is to fill up the grid with data to the extent of the ScrollHeight property. Then, as you scroll down, RadGrid makes a request for additional data and displays that section of the grid. If virtual scrolling is not enabled, all data rows are returned and stored in the grid. Virtual scrolling improves initial load time when using large datasets, but will be slightly less smooth during scrolling when data is retrieved.
512
2. In the Properties View of the RadGrid, go to the MasterTableView property and expand it, and then change the CommandItemDisplay property to "Top".
This will add a header to the top of the RadGrid that has an "Add" button and that will allow you to put the grid into an insert mode.
3. Next you need to set an edit mode for the table view. Go to the MasterTableView property in the Properties View, expand it and change the EditMode property to "InPlace". This is the simplest mode to use if you do not have any complex data entry requirements. 4. Now run the web application and play with the add, edit, select and delete buttons. You will see that the add and edit buttons create a row of entry fields to edit or change data based on the EditMode property "InPlace". You will also note that none of the buttons actually do anything to the data. 5. Close the web application and configure the datasource for the RadGrid.
513
7. In the UPDATE, INSERT and DELETE tabs, enter the following queries: [T-SQL] Update UPDATE Purchasing.[Vendor] SET [AccountNumber] = @AccountNumber, [Name] = @Name, [CreditRating] = @CreditRating, [PreferredVendorStatus] = @PreferredVendorStatus, [ActiveFlag] = @ActiveFlag, [PurchasingWebServiceURL] = @PurchasingWebServiceURL, [ModifiedDate] = @ModifiedDate WHERE [VendorID] = @VendorID [T-SQL] Insert INSERT INTO Purchasing.[Vendor] ([AccountNumber], [Name], [CreditRating], [PreferredVendorStatus], [ActiveFlag], [PurchasingWebServiceURL], [ModifiedDate]) VALUES (@AccountNumber, @Name, @CreditRating, @PreferredVendorStatus, @ActiveFlag, @PurchasingWebServiceURL, @ModifiedDate) [T-SQL] DELETE FROM Purchasing.[Vendor] WHERE [VendorID] = @VendorID 8. Click Next and Finish. 9. Finally, in the RadGrid properties view, go to the Data Editing section and turn the following three properties to true. This will allow the grid to automatically use the provided SQL statements to perform these actions.
Now when you run the application you will be able to perform all of the edit, add and delete functions and you never had to leave the designer.
514
RadGrid.ClientSettings: Provides access to the client-side events and properties. RadGrid.*Style: Allows change to the appearance of the various interfaces of the RadGrid that applies to the entire hierarchy of GridTableViews unless overridden by a non-default setting.
515
RadGrid.MasterTableView: This is the base level GridTableView of the RadGrid, which is the only table you will work with if there are no details or hierarchal tables.
The next properties are important to every every GridTableView including the MasterTableView:
GridTableView.DetailTables: The collection of GridTableViews that make up the sub-tables of a GridTableView. GridTableView.*Style properties: The individual settings of the GridTableView that will override any settings in the RadGrid.*Style settings. GridTableView.GroupByExpressions: Add or remove objects to this collection to set grouping programmatically. GridTableView.SortExpressions: Add or remove objects to this collection to set sorting programmatically. GridTableView.Columns: Access the Columns collection created at design-time. GridTableView.AutoGeneratedColumns: Collection of columns created at run-time. GridTableView.RenderColumns: Collection of all columns created at design-time and runtime including interface columns such as expand/collapse and group splitters.
Action
Events in the "Action" group of properties happen in response to interface interaction:
*Command: ItemCommand, CancelCommand, DeleteCommand, EditCommand, InsertCommand, UpdateCommand and SortCommand. ItemCommand is a catch-all for any clicked RadGrid button such asEdit, Delete, or Update command events.The other commands are operation specific, e.g. DeleteCommand fires when aDelete command bubbles up. All these events except for SortCommandpass a GridCommandEventArgs object. GridCommandEventsArgscontains a Canceled propertythat you can set to kill the event, CommandName to help determine the kind of operation to expect, CommandArgument, Item, andCommandSource.CommandSource isa reference to the control that triggered the command. For example, the control might be a button that triggered an Expand or Collapse command. Item is a GridItem type that may be cast to an type appropriate for the event, i.e. GridEditableItem during the Update command. Here's a brief extract from a Update command event handler that shows the Item event argument in play: [VB] Handling the UpdateCommand Event
516
PageIndexChanged: Fired when a page selection arrow is clicked. GroupsChanging: Fired when a grouping is created or removed. You can use this event to hide or unhide columns that are being used for grouping. RowDrop: Fires when a grid row is dragged and dropped. To make this event fire, set the ClientSettings.AllowRowsDragDropproperty and the ClientSettings.Selecting.AllowRowSelect propertyto true. The example below shows a row with product information being dropped at another location in the same grid and an alert reporting the ProductID of the dragged row. Also be aware that the arguments passed in contain a list of the dragged items, the identity of the grid being dragged onto, the DropPosition (Above, Below), and HTMLElement (the ID of an HTML element that the row was dropped on). [VB] Handling the RowDrop Event Protected Sub RadGrid1_RowDrop(ByVal sender As Object, ByVal e As Telerik.Web.UI.GridDragDropEventArgs) Dim item As GridDataItem = TryCast(e.DraggedItems(0), GridDataItem) RadAjaxManager1.Alert("Dropped ProductID: " + item.GetDataKeyValue("ProductID")) End Sub [C#] Handling the RowDrop Event protected void RadGrid1_RowDrop(object sender, Telerik.Web.UI.GridDragDropEventArgs e) { GridDataItem item = e.DraggedItems[0] as GridDataItem;
517
For info on the NeedDataSource and DetailTableDataBind events, see the Data section below.
Behavior
Events in the "Behavior" group of properties can be used to intercept and alter elements of the RadGrid before or after they are created.
ItemCreated: Fired on the server when an item in the RadGrid control is created. ItemDataBound: Fired after an item is databound to the RadGrid control. ColumnCreating: Fired before a custom column is being created. ColumnCreated: Fired after an auto-generatedcolumn is created.
Data
Events in the "Data" group of properties respond to databinding and CRUD (Create, Remove, Update, Delete) operations.
DataBinding: Fired right before the server control binds to a data source. DataBound: Firedwhen the server control is bound to a data source. These next two appear in the Action group, but we're including them here along with the other data related events:
NeedDataSource: Fired when RadGrid needs adata source for rebinding. This event can be useful when the data source may change at runtime or you for some reason don't want to set the data source declaratively. In this event youwould set the DataSource property, not the DataSourceID. DetailTableDataBind: Fired when a DetailsTablebindsto a data source.
Data Editing
These events ItemInserted, ItemUpdated and ItemDeleted, fire right after automatic inserts, updates and deletes. The arguments passed into these events all descend from GridDataChangeEventArgs and arevery similar to one another.The arguments includean integer number of the AffectedRows, an Exception object, a
518
Misc / Exporting
The events in this group handle exporting behavior.
GridExporting: Fires when the grid exports to any output type. The event arguments include OutputType, an enumeration that indicates the format, e.g. Excel, MSWord, etc., and ExportOutput, a string that will be output to the Response. Excel specific events ExcelExportingCellFormatting, ExcelMLExportRowCreated, ExcelMLExportStyesCreated.
519
5. Configure a new datasource for the RadGrid. 6. Connect to the NorthWind database and save the connection string. 7. Choose the "Shippers" table and select all of the rows (*) for the SELECT query.
8. Click Next | Test Query | Finish. 9. Open the Smart Tag and select the Auto-generate edit column at runtime and Auto-generate delete column at runtime options.
520
11. In the Properties View, navigate to Layout | MasterTableView | CommandItemDisplay and set it to "Top". 12. In the Properties View for the RadGrid go to the events tab and double click on the DeleteCommand event. 13. Add the following code to the event handler: [VB] DeleteCommand event handler 'Get the GridDataItem of the RadGrid Dim item As GridDataItem = DirectCast(e.Item, GridDataItem) 'Get the primary key value using the DataKeyValue. Dim ShipperID As String = item.OwnerTableView.DataKeyValues(item.ItemIndex) ("ShipperID").ToString() Try 'Delete command execute SqlDataSource1.DeleteCommand = "DELETE from Shippers where ShipperID='" + ShipperID + "'" SqlDataSource1.Delete() Catch ex As Exception RadGrid1.Controls.Add(New LiteralControl("Unable to delete Shipper. Reason: " + ex.Message)) e.Canceled = True End Try [C#] DeleteCommand event handler //Get the GridDataItem of the RadGrid GridDataItem item = (GridDataItem)e.Item; //Get the primary key value using the DataKeyValue.
521
522
523
2. In the Properties View, go to the events tab for the RadGrid and double-click on ItemDataBound. 3. Now simply add this code to the event handler: [VB] Converting a data field to an image
524
525
Properties
You will need to access either column or row client objects in the GridTableView to manipulate data, appearance and behavior. The following are properties accessible in the client-side API that you would most likely use to access and alter elements of the RadGrid and that grid's GridTableViews. To get the main RadGrid object, pass the grid's ClientID to the $find() method: var grid = $find("<%= RadGrid1.ClientID %>"). To get thegrid's root GridTableView object, use the get_masterTableView()method. Likewise you can get at the grid header, footerusing get_masterTableViewHeader() and get_masterTableViewFooter(). [JavaScript] Getting TableView, Header and Footer Client Objects var tableView = $find("<%= RadGrid1.ClientID %>").get_masterTableView(); var header = $find("<%= RadGrid1.ClientID %>").get_masterTableViewHeader(); var footer = $find("<%= RadGrid1.ClientID %>").get_masterTableViewFooter(); Once you have the the MasterTableView object you can call it's client methods. Here's an example that calls the exportToExcel() method: [JavaScript] Exporting to Excel function exportGrid() { var masterTable = $find("<%=RadGrid1.ClientID %>").get_masterTableView();
526
get_owner(): This property is of type RadGrid and is the parent of the current object. get_element(): Returns an HTML table which represents the respective table for the GridTableView object rendered on the client. get_dataItems(): A collection which holds all data items (objects of typeGridDataItem)in the respective table. get_columns(): A collection which holds objects of type GridColumn (the client-side objects)in the respective table. get_name(): String which represents the Name property (set on the server) for thecorrespondingGridTableView client object. Can be used to identify table in grid hierarchy client-side. get_selectedItems(): A collection which holds all selected items (objects of type GridDataItem) in the respective table. This collection will also include the selected items from child tables if they exist. get_isItemInserted(): Boolean value returns true if the table is in insert mode. get_pageSize(), set_pageSize(): The page size for the respective GridTableView object. get_currentPageIndex(), set_currentPageIndex:The current page index for the respective GridTableView object. get_pageCount():Returns the page count for the respective GridTableView object. get_clientDataKeyNames(): One-dimensional array which holds the key fields set through the ClientDataKeyNames property of GridTableView on the server. To extract the key values you can use the eventArgs.getDataKeyValue inside any row-related client event handler of RadGrid. get_parentView(): If called from a nested table view returns the parent table view (of type GridTableView) in the grid hierarchy; returns null if called from the MasterTableView. get_parentRow():If called from a nested table view returns the parent row (html table row: <tr>) for the current nested hierarchical table view; returns null if called from the MasterTableView.
You can further refer to the elements of the RadGridTable using the functions below: <GridTableViewInstance>.get_columns()[n].get_element(): the real HTML table column for the n-th column (<th> for header cell) <GridTableViewInstance>.get_dataItems()[n].get_element(): the real HTML table row for the n-th row (<tr> element) Here's an example that iterates the master table view selected items and shows the inner text of each. [JavaScript] Iterating Selected Items function showSelectedRows() { var dataItems = $find("<%=RadGrid1.ClientID%>").get_masterTableView().get_selectedItems(); for (var i = 0; i < dataItems.length; i++) {
527
RadGrid Events
You can follow the life-cycle of the grid using the OnGridCreating, OnGridCreated and OnGridDestroying client events. [JavaScript] Handling the OnGridCreating Event function gridCreating(sender, args) { alert("creating: " + sender.ClientID); }
GridTableView Events
The following shows some of the key events for the GridTableView (either the MasterTableView or any of the detail tables). For a more complete list, consult the online help.
Creation
Like the RadGrid object, GridTableViewhas events that follow the life cycle of these objects OnMasterTableViewCreating, OnMasterTableViewCreated, OnColumnCreating, OnColumnCreated, OnColumnDestroying,OnRowCreating, OnRowCreated andOnRowDestroying.
Columns
You can find out when columns are resized, reordered,hidden,clicked, when the mouse hovers over a column orwhen a context menu appears for a column heading:
OnColumnResizing, OnColumnResized: These events fire before and after a column is resized. OnColumnSwapping, OnColumnSwapped: These events fire before two columns are swapped. OnColumnMovingToLeft, OnColumnMovedToLeft, OnColumnMovingToRight, OnColumnMovedToRight: These events fire before and after columns are moved left or right. OnColumnClick, OnColumnDblClick: These events fire before and after a column is clicked. OnColumnMouseOver, OnColumnMouseOut: These events fire when the mouse first hovers over a column and then moves away from the column. OnColumnShowing, OnColumnShown: These events fire before and after a column is shown. OnColumnContextMenu: This event is fired when the context menu for a column is called. OnColumnHiding, OnColumnHidden, OnColumnShowing, OnColumnShown: These events fire before and after acolumn changes visibility.
Rows
A parallel set of events exist for grid columns:
OnRowResizing, OnRowResized: These events fire before and after arow is resized. OnRowSelecting, OnRowSelected, OnRowDeselecting, OnRowDeselected: These events occur before and after the row selection is toggled.. OnRowClick, OnRowDblClick: These events fire when a row is clicked/double-clicked. OnRowMouseOver, OnRowMouseOut: These events fire when the mouse first hovers over a row and again when the mouse leaves the row. OnRowContextMenu: This event is fired when the context menu for a row is called. OnRowShowing, OnRowShown, OnRowHiding, OnRowHidden: These events fire before and after a row's
528
OnRowDeleting, OnRowDeleted: These events fire before and after a row is deleted (client-side delete).
Rows have an additional set of events to handle drag and drop operations on the client side:
OnRowDragStarted: This event is fired when a row is about to be dragged. OnRowDropping: This event is fired before a row is dropped. OnRowDropped: This event is fired after a row is dropped.
OnActiveRowChanging: This event is fired before the active row change. OnActiveRowChanged: This event is fired after the active row is changed.
And finally, you can be notified when a row is about to be bound on the client using OnRowDataBound.
Command
OnCommand: This event is fired for each grid command which is about to be triggered (sorting, paging, filtering, editing, etc.) before postback/ajax request .
Methods
After you have retrieved the column or data item that you want to change, these are the methods you will most likely call to affect that change.
selectItem (gridItem), deselectItem(gridItem): The row passed as an argument will become selected/deselected. hideItem(index), showItem(index): Hide or show the row at the indexed position. expandItem(index), collapseItem(index): Expand or show the indexed row. If the index corresponds to nested table item, all parent items will be expanded to top. Applicable for HierarchyLoadMode = Client only!
[JavaScript] Collapsing an item function CollapseFirstDetailTableFirstItem() { $find("<%= RadGrid1.Items[0].ChildItem.NestedTableViews[0].ClientID %>").collapseItem(0); } If you haveitems selected in the grid, you can call methods to clear, edit, update anddelete the selected items all at once:
clearSelectedItems():Method which clears the selected items for the respective GridTableView client object. This method will clear the selected items from the table's child tables (meaningful in hierarchical grid only). editSelectedItems():Method which switches all selected items in the grid in edit mode.
529
updateSelectedItems(): Method which updates all edited items in the grid. The new data will be taken from the edit form editors. deleteSelectedItems():Method which deletes all selected items in the grid.
[JavaScript] Deleting a selected item function DeleteSelectedGridItems() { var masterTable = $find("<%= RadGrid1.ClientID %>").get_masterTableView(); masterTable.deleteSelectedItems(); } You can set the grid's edit mode using GridTableView methods:
showInsertItem():Method which switches the grid in insert mode and displays the insertion form. cancelUpdate(gridItem): Method which cancels the update for the edited table row passed as an argument or the row corresponding to the index passed as an argument. If you have several items switched in edit mode, you can cancel the update for all of them with subsequent calls to this method. cancelInsert(): Method which cancels the insert action and switches the grid in regular mode. editItem(gridItem): Method which switches the table row passed as an argument or the row corresponding to the index passed as an argument in edit mode. If you set AllowMultiRowEdit to true, you can switch multiple grid items in edit mode with subsequent calls to this method. editAllItems(): Method which switches all GridDataItems in edit mode. cancelAll():Cancels the edit mode for all grid items that are switched in edit mode prior to the method call.
[JavaScript] Using cancelAll() function CancelEditMode() { var masterTable = $find("<%= RadGrid1.ClientID %>").get_masterTableView(); masterTable.cancelAll(); } ...and you can perform CRUD operations directly on the client. The data for insertion or update is taken from the form editor's fields.
deleteItem(gridItem): Method which deletes the table row passed as an argument or the row corresponding to the index passed as an argument. updateItem(gridItem): Method which updates the edited table row passed as an argument or the row corresponding to the index passed as an argument. If you have several items switched in edit mode, you can update all of them with subsequent calls to this method. insertItem(): Method which inserts new table row to the grid.
[JavaScript] Using insertItem() function AddNewItem() { var masterTable = $find("<%= RadGrid1.ClientID %>").get_masterTableView(); masterTable.insertItem(); }
530
swapColumns(colUniqueName1, colUniqueName2): The columns with unique names colUniqueName1 and colUniqueName2 will be swapped. reorderColumns( colUniqueName1, colUniqueName2): colUniqueName1 is the "from" unique name of the table column while colUniqueName2 is the "to" unique name of the column (i.e. the new location). moveColumnToLeft(columnIndex), moveColumnToRight(columnIndex): The column at the specified columnIndex will be moved to the left or right. hideColumn(columnIndex), showColumn(columnIndex): Hide or show the column at the specified columnIndex position. groupColumn(colUniqueName), ungroupColumn(colUniqueName):Group or un-group by the column with specified UniqueName.
Client-side databinding
RadGrid for ASP.NET AJAX supports client-side binding to web services or page methods as demonstrated in this (http://demos.telerik.com/aspnet-ajax/grid/examples/client/declarativedatabinding/defaultcs.aspx) and this (http://demos.telerik.com/aspnet-ajax/grid/examples/client/databinding/defaultcs.aspx) online demo of the product. In order to assign data source for the grid and refresh its state on the client, utilize the set_dataSource(dataSource) (http://www.telerik.com/help/aspnet-ajax/set-datasource.html) and dataBind () (http://www.telerik.com/help/aspnet-ajax/databind.html) methods from its client-side API. Keep in mind that the data source passed as an argument to the set_dataSource method should have JSON signature which can be serialized by a web service or a page method. The following exampledemonstrates how to find a control on a web form and load data into a grid on the client. You can find the complete source for this project at: \VS Projects\Grid\RadGridClientSideAPI Databinding on the client only works in RadControls for ASP.NET AJAX 2008 Q2 and later. 1. First, create a new web application. 2. You will need an XML file that contains sets of values. In this examplewe have an XML file that I have put inthe App_Data folder of the project with values that look like the screenshot below. You can get this file in the complete demonstration or create your own:
531
3. Add the Contact class definition listed below. You can place this in a separate Contact.cs file or to the end of the default web page code-behind. [VB] The Contact class used to define the data structure Public Class Contact Private _ID As Integer Private _Name As String Private _Age As Integer Private _Sex As String Private _Email As String Private _Phone As String Public Property ID() As Integer Get Return Me._ID End Get Set(ByVal value As Integer) Me._ID = value End Set End Property Public Property Name() As String Get Return Me._Name End Get Set(ByVal value As String) Me._Name = value End Set End Property Public Property Age() As Integer Get Return Me._Age End Get Set(ByVal value As Integer) Me._Age = value End Set End Property
532
533
534
[ASP.NET] Javascript functions for databinding <script type="text/javascript"> function pageLoad(sender, args) { // Load data from web service PageMethods.GetData(updateGrid); } function updateGrid(result) { var tableView = $find("<%= RadGrid1.ClientID %>").get_masterTableView(); tableView.set_dataSource(result); tableView.dataBind(); } function RadGrid1_Command(sender, args) { // Handle the RadGrid's Command event here } </script> 12. Add a reference to the OnCommand event in the markup as shown below. [ASP.NET] OnCommand event binding <ClientSettings> <ClientEvents OnCommand="RadGrid1_Command" /> </ClientSettings> As of this writing, handling the OnCommand event is required to avoid errors. It's expected that in later versions of the product that this limitation will be removed. Now when you run the application you should see a fully populated grid.This code takes as much of the burden of databinding to the client as possible.
535
536
537
This example is a great reference for using the RadGrid in client-side code, asretrieving values, setting events
538
19.7 Summary
In this chapter you looked at the RadGrid control and saw some of the powerful features it provides. You created a simple application that bound the grid to live data and manipulated the auto-generated columns. You also explored the most fundamental features of the RadGrid such as Sorting, Filtering, Grouping andPaging. You worked with an example of implementing CRUD maintenance manually in server-side code. You learned how to access data values and manipulatedthe appearance of a columnin server-side code by replacing cell values with an HTML image tag. You implemented the powerful new client-side databinding feature of the RadGrid which showed the overwhelming versatility of the RadGrid to bind to any form of data. Finally, you learned some advanced client-side coding techniques, including accessing data values, manipulating appearance and binding to client-side events to make a responsive and flashy interface.
539
20.1 Objectives
Explore features of the Editor control. Learn how to configure RadEditor for the runtime environment. Explore the RadEditor design time interface including the Smart Tag and major property groups. Learn how to configure the tools file. Learn some advanced tasks including creating custom modules, content filters, buttons and drop down lists. You will also learn how to optimize for multiple editors and localize RadEditor for international use. Learn how tocontrol RadEditor using theclient API.
20.2 Introduction
RadEditor is a powerful but lightweight editor control you can use in your web applications where you need a full-featured editor, not a text box. It comes loaded with lots of built-in goodies like pre-defined buttons, drop down lists, File Browser dialogsand context menus that perform any tasks you are likely to need. If the built-in tools don't fill the bill, RadEditor can be extensively customized. Some of the hottest features are:
Unmatched Loading Speed Minimal Script Size New Semantic Rendering Out-of-the-box XHTML-enabled Output Industry-best Cross-browser Support Single-file, Drag-and-drop Deployment (all editor resources, including the dialogs reside in the same dll) Multilevel Undo/Redo with Action Trails 7 Ways to Paste from Word AJAX-Based File Browser Dialogs Full keyboard accessibility Flexible Skinning mechanism Simplified and intuitive toolbar configuration Ability to have editors with different skins on the same page
540
541
3. Locate the RadControls installation directory \App_Data folder and copy the contents to your project's \App_Data folder. Note: You really only need to copy the en-us.tdf dictionary file to allow spell checking.
4. This next part is not "minimal", but is still included here. From the Smart Tag, drop down the list of Skins and select the "Vista" skin. 5. Press Ctl-F5 to run the application. In the example below, some marketing text has been pasted to editor. You can paste any text or HTML that is on your clipboard using the paste button. Try clicking the spell check button. The spell check occurs right in the editor content area and drops down a list of suggestions at each misspelled word with the industry standard options for Ignore, Add to
542
Try clicking the Find button and locate some string of text. The option that allows the Find dialog to appear, or any other dialog that RadEditor supports, is enabled by the Smart Tag option you took labeled "Enable RadEditor Dialogs".
RadEditor Elements
RadEditor is made up of toolbars, the content area and various modules. The toolbar in turn contains buttons, dropdown lists, toolstrips and dialogs.
543
Toolbars: The main elements of RadEditor are the Toolbars. They are in fact containers, which accommodate the buttons and dropdown lists of the various tools. Buttons: Used to edit content, to launch different dialogs, to Undo / Redo the content, save or cancel the changes, etc. Dropdowns: Used to format the font appearance (family, size, color, apply css class) as well as to insert objects into the content area such as html code snippets. ToolStrip: Dropdowns that contain a group of tools with related functionality and can be a very convenient means of arranging tools used in the editor. Dialogs: Used to insert objects into the content area such as images, links, media and flash files. Context Menus: Shortcut menus that include commands associated with objects on the screen. With RadEditor, you can use the default context menus as well as specify custom menus for various HTML elements (e.g. different context menus for images, tables, hyperlinks etc.) You can also disable the context menus for certain elements (e.g. for tables). Modules: Special tools used to provide extra information such asDom Inspector, real time HTML Viewer, Statistics module Editor Mode buttons: Used to switch between the editor's viewing modes: Design, HTML and Preview. Resize Handle: Lets the user drag the editor boundaries within the browser.
Smart Tag
544
Properties Window
The most important property is Content.Content can be assigned any text orany HTML.As a user, you can copy and paste HTML directly from the clipboard to the editor.Programmatically, you canjust assign to the Content property: [VB] Assigning Content RadEditor1.Content = "<H1>RadEditor Properties</H1><ul>" + "<li>Content</li>" + "<li>ToolbarMode</li>" + "<li>AutoResizeHeight</li></ul>" [C#] Assigning Content RadEditor1.Content = "<H1>RadEditor Properties</H1><ul>" + "<li>Content</li>" + "<li>ToolbarMode</li>" + "<li>AutoResizeHeight</li></ul>";
545
RadEditor has an extensive set of properties, but we can group some of these to make it easier to navigate. In the Properties Window, click the Categorized button to follow along. We won't look at every single property or group of properties, but try to get a feel for where the significant properties are found.
Appearance
This group of properties controls appearance on several levels:
Individual property settings such as BorderColor, BorderWidth, ForeColor, etc. These properties will work in limited scenarios where the styles or skins are not already at work and where you have a property that already addresses the visual change you need to make. CSS styles: You can set CssClass to assign a style to the control as a whole. You can also point ContentAreaCssFile to a file name that holds styles for the content area. Skins: You can set the Skin to an predefined value to get a coordinated look-and-feel. You can also customize an existing skin or build your own from scratch.Skins provide a generalized framework for changing editor appearance so that it works with the other controls in your application.
Behavior
ContentFilters list a set of JavaScript objects that can be enabled to act on the content when submitting a page or when switching between Design and HTML views. For example, if no filters are activated, we can add a JavaScript tag in the editor, move between HTML and normal views and the JavaScript will actually execute.The screenshot below shows the script entered in HTML mode.
546
The next screenshot shows what happens when you navigate back to the Design tab and then back to the HTML tab.
When you select the RemoveScripts content filter, the script is completely removed when you move between edit modes. You can add this at design time from the Property window:
547
In code you can combine these flags using the bitwise OR operator: [VB] Assign Content Filters RadEditor1.ContentFilters = Telerik.Web.UI.EditorFilters.MakeUrlsAbsolute Or Telerik.Web.UI.EditorFilters.FixEnclosingP [C#] Assign Content Filters RadEditor1.ContentFilters = Telerik.Web.UI.EditorFilters.MakeUrlsAbsolute | Telerik.Web.UI.EditorFilters.FixEnclosingP; Using the Behavior properties you can also:
Turn off the EnableResize property to prevent the user from changing the editor dimensions. Toggle the NewLineBr property. NewLineBris true by default which means that every time the user hits Enter, a <br> tag is generated. If you set NewLineBr false, each line is surrounded with page <p> tags. Configure the StripFormattingOptions property to one or more of these values: None, NoneSuppressCleanMessage, MSWord, MSWordNoFonts, MSWordRemoveAll, Css, Font, Span, AllExceptNewLines and All. These can be selected from the Properties window or use the bitwise OR operator to combine these values. When you paste from MS Word with this property set to "None", you get quite the formatting circus:
With this property set to the other extreme of "All", you get simple HTML elements only:
548
Change the ToolBarMode property from Default, where the tool bar is static and positioned over the content area to PageTop, ShowOnFocus or Floating. If you use PageTop, the toolbar docks to the top of the entire web page, so that if you have multiple editors open, the one toolbar applies to all. This screenshot shows PageTop with two editors.
ShowOnFocus will cause the ToolBar to appear right above the editor when it gets focus. Later we will talk about how ShowOnFocus can be used together with the ToolProviderIDfor awesome performance when loading multiple editors on the same page. Floating will cause the toolbar to pop up in a window and will allow the user to move it over the page. This next screenshot is an example of the floating toolbar:
549
Client-Side Events
We will explore these events in the upcoming section on Client-Side Programming. For now, just know the events fire on the client when editor is first initialized and loaded, and when the user causes events to fire, i.e. when commands are executing, a paste is in process or when the text selection changes.
Dialog Configuration
RadEditor dialogs are used to insert objects into the content area. These "FileBrowser" dialogs handle images, Flash, documents, Silverlight, media and templates. The FileBrowser dialogs consist of a FileBrowser object, an object previewer/property manager and a file uploader tab. The FileBrowser provides the ability to browse directories and locate a file item. Selected file items are loaded into the previewer. This Dialog Configuration section of the Properties Window has a number of "Manager" properties that correspond to dialogs.
550
The sub-properties are similar between specific managers. The ContentProviderTypeNameallows you to create your own dialog manager by inheriting from FileSystemContentProviderand plugging it in to this property. The various "paths" properties determine what files can be seen by the dialog:
ViewPaths specifies where files are located. The dialog will display all files found in this directory and children of this directory. UploadPaths specifies where users can upload files. To be visible, these paths need to be within "ViewPaths". DeletePaths specifies where users can delete files. Again, these paths need to be within the "ViewPaths" paths to be visible.
For example, the markup that defines the ImageManager paths shows the base path, that is ViewPaths is the "images" directory, files can be uploaded to "images/new" and files can be deleted from "images/new/articles" and "images/new/news". [ASP.NET] Defining Dialog Paths <telerik:radeditor runat="server" ID="RadEditor1" > <ImageManager ViewPaths="~/Images" UploadPaths="~/Images/New" DeletePaths="~/Images/New/Articles,~/Images/New/News" />
551
New String() {"~/Common"} = New String() {"~/Common"} = New String() {"~/Common", "~/Marketing"}
new string[] { "~/" }; = new string[] { "~/" }; = new string[] { "~/" }; new string[] { "~/Common" }; = new string[] { "~/Common" }; = new string[] { "~/Common", "~/Marketing" }; new string[] { "~/Common/Resources" }; = new string[] { "~/Common/Resources" }; = new string[] { "~/Common/Resources",
The last couple of properties for a dialog manager are SearchPatterns, thatdefines a list of extensions that can be displayed by a dialog and MaxUploadFileSize that controls the maximum allowed file size.
DropDown Configuration
The DropDown Configuration section of properties are collections that populate drop down lists within the
552
Clicking the ellipses for any of these properties brings up a collection editor that will allow you to define members of the collection. Properties for each member are specific to the kind of members being defined, like the context menu editor collection shown in the image below.
Tools
During the "Getting Started" section on "RadEditor Elements" we talked about how the editor was made up of Tools, Modules and content. The Tools category of properties controls what tools and modules you will see. The tools can be defined by either the Tools collection or by specifying an XML file and pointing to it with the ToolsFile property.
If you go the Tools collection route and click the ellipses for this property the "EditorToolGroup Collection Editor" displays. From there you can create tool groups. For each group you click the Tools collection to display
553
As you can see from the next screenshot, the tools defined in the Tools collection or from the ToolsFile completely replace the default tool set.
When you click the Modules collection ellipses, the EditorModule Collection Editor displays. You can add modules and select the Name property from the drop down list.
554
555
556
ContentAreaMode="DIV" mode:
The DIV element is part of the current page and the page CSS styles will be directly imported and applied to the content area and the contents in it. In order to customize the content area appearance of the RadEditor in Div mode, register the CSS selectors manually on the page with the appropriate cascading (.reContentArea <global selector: P, FORM, IMG, TABLE, TR, TD, H1-H6, etc>), e.g. .reContentArea/*thisselectorcorrespondstothebodyselectorwhenRadEditorisinIframemode*/
557
558
3. Locate the RadControls installation directory \App_Data folder and copy the contents to your project's \App_Data folder. 4. From the Solution Explorer, right-click the project and select Add Item from the context menu.Select the XML typeand name the file "MyTools.xml". 5. Add the following to MyTools.xml: [XML] Defining the ToolsFile
559
You can find the complete source for this project at:
560
There are some RebbonBar related properties which are added for the tools and tool xml elements in the editor's ToolsFile file (Section 20.7):
For the tools elements the "name" property sets the RibbonBarGroup control, in which the tool is loaded and the "tab" property sets the RibbonBarTab control, in which the group is loaded. For the tool elements the "size" property sets the size of the buttons.
You can review the tools.xml file below for more information: tools.xml configuration file <?xml version="1.0" encoding="utf-8" ?> <root> <modules> <module name="RadEditorStatistics" dockingZone="Bottom"/> <module name="RadEditorDomInspector" />
561
562
563
564
Events
FileDelete and FileUpload
If you have one of the file browser dialog managers configured so that files can be viewed, uploaded or deleted, the FileDelete and FileUpload events can fire. You can cancel the delete or uploaded based on the parameters passed to the event."Sender" is the dialog object instanceand can be used to know which dialog initiated the event, for example: if (sender is Telerik.Web.UI.Editor.DialogControls.DocumentManagerDialog) { ... } The "fileName" is the path of the file as it will used by the editor. In the example below "MyDocuments" is a directory within the web application project, not the local drive being uploaded from. If the user is uploading or deleting within a "Document Manager" dialog, then we process some special logic. The FileUpload event handler allows the upload only if the file doesn't already exist. The FileDelete event handler allows the file to be deleted only if the path ends with a ".sav" extension. If this is dialog other than the "Document Manager", always perform the upload or delete operation.
565
20.10Client-Side Programming
Getting Client Object References
As with all the RadControls, you can get a client reference to the editor using the $find() method: var editor = $find("<%=RadEditor1.ClientID%>"); From there you can use get_document() get references to the editor document: var document = editor.get_document(); Use the document objectto execute browser commands. execCommand() has three parameters:
The command name. An optional property that if true, displays a user interface (if the command supports one). An optional property for passing a value.
In the example below we call the "Bold" command with no user interface or values being passed. Any selected text will be bolded [JavaScript] Using execCommand() function ApplyBold() { // return a reference to RadEditor var editor = $find("<%=RadEditor1.ClientID%>"); // get a reference to the editor's document var document = editor.get_document(); // execute a document command document.execCommand("Bold", false, null); }
566
567
568
7. Click OK twice to close both collection editors. 8. In the ASP.NET markup for the page, add the style below inside the <head> tag. [ASP.NET] Adding the Custom Tool Button Image <style type="text/css"> .rade_toolbar.Default .MyCustomTool { background-image: url("arrow.png"); } </style> Gotcha! Be careful to keep the space between ".rade_toolbar.Default" and".MyCustomTool". They are two different CSS selectors, not one long string.
9. Add the script below. This bit of script actually assigns the function to the editor's CommandList but does not run it. The MyCustomTool command runs when the button is clicked. The command executes a pasteHtml() method that in turn drops in a horizontal rule tag. [JavaScript] Define the Button Command Functionality <script type="text/javascript"> Telerik.Web.UI.Editor.CommandList["MyCustomTool"] = function(commandName, editor, args) { editor.pasteHtml("<hr>"); }; </script>
569
570
20.11How To
Optimization for Multiple RadEditors
Starting in version 2008.1.619, RadEditor has substantial tools loading performance improvements. The big benefit comes when you have multiple RadEdit controls on the page. In the past there would be markup defined for each toolbar so that the more edit controls on the page, the longer it would take to load from the server and render in the browser. Now, thanks to anew property ToolsProviderID,the toolbar is defined for one editor and the other editors use only that toolbar. Use ToolsProviderID together with the ToolBarMode ShowOnFocus or PageTop to get even more performance improvement. This next example should give you a gut feel for how these properties work together by toggling them and resubmitting the page. When using the default Toolbar Mode and not supplying a ToolsProviderID, notice how even after the editors are loaded on the page, the toolbars still take extra time to finish loading.
571
1. Create a ASP.NET Web Application. 2. Add the following markup to define the checkboxes and submit button. [ASP.NET] Adding Checkboxes and Submit Button <ul style="padding: 0; margin: 0; list-style: none;"> <li> <asp:CheckBox ID="UseToolProvider" runat="server" Checked="false" Text="Use Tool Provider" Title="Use Tool Provider" /></li> <li> <asp:CheckBox ID="UseShowOnFocusToolbarMode" Checked="false" Text="Use ShowOnFocus Toolbar Mode" runat="server" Title="Use ShowOnFocus Toolbar Mode" /></li> </ul> <p> <asp:Button ID="SubmitButton" runat="server" Text="Apply Settings" title="Apply Settings" /> 3. Add five RadEditor controls below the submit button. 4. In the code-behind, add a Form_Load event handler: [VB] Configuring the Editor Controls Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) ' track the first editor Dim firstEditor As RadEditor = Nothing
572
573
You can find the complete source for this project at: \VS Projects\Editor\ToolProviderID You can also find this project with additional JavaScript code that provides specific timings at the ToolProviderID demo (http://demos.telerik.com/ASPNET/Prometheus/Editor/Examples/ToolProvider/DefaultCS.aspx).
Localization
All the language for the editor user interface can be automatically translated to either a built-in language or a translation you provide. Localization not only takes care of the text for each UI element, but also supplies a translated tool tip. Localization can be specified...
Using resource files that come with the installation found in "\RadControls for ASPNET AJAX <version>\App_GlobalResources" or using your own resource files. The "built-in" resource files are translations for English, French and German that come with the RadControls installation. Using the Localization property to set specific strings for Dialogs, Main, Modules and Tools programmatically. Localization settings override the resource file settings. If you have a tools file defined, you can also call the RadEditor FindTool() method and set the text for a specific tool.
The order of precedence for localization is generally that Text assigned at runtime (in the Page_Load for
574
7. Set the RadEditor Language property to "Fr-fr" 8. Press Ctl-F5 to run the application.Notice that both the text and tool tips display in French.
You can find the complete source for this project at: \VS Projects\Localization\Localization
575
The culture name has to follow the RFC 1766 standard in the format [Language Code]-[County/Region Code]. In our example, it-IT stands for Italian - Italy. All resx file contain two columns Name and Value as shown in the screenshot below. Leave the Name as-is and change the Value for each of these to the target language.
576
Gotcha! You must add at least one of the built-in modules when you create a custom module. Due to optimization, the editor will not register the custom modules javascript code if a built-in module is not declared. When the JavaScript tries to register your custom class it will fail with an error that ModuleBase was null.
2. Add a JavaScript class with the same name as the custom module right below the RadEditor markup. The constructor takes a single parameter "element". Within the constructor, call the ModuleBase initializeBase() method passing a reference to the module and the element. In the prototype, add two methods. The first, initialize(), extends an inherited method from ModuleBase. In this initialize() method, call the inherited method, then hook up the SelectionChange event of the editor to a method to be defined next called doSomething().Also call doSomething() once explicitly to cause the module to display immediately. In the doSomething() method, create a SPAN element and load it with the contents of the RadEditor's html. Using the span getElementsByTagName() method, get a count of all the break "<br>" tags in the html. Finally display and format an informational method within the modules element that shows the number of breaks encountered so far. [JavaScript] Adding the Custom Module Script <script type="text/javascript">
577
578
579
If filtering were initiated during Design mode, then entering or pasting large content would be in danger of slowing down or crashing the browser. For best typing, formatting and editing performance, the editor's content filters act only when switching to Html mode or when submitting the content. You can find the complete source for this project at: \VS Projects\Editor\ContentFilter
20.12Summary
In this chapter we explored the RadEditor's rich feature set, learned how to configure RadEditor for the runtime environment and looked at the editor's design-time interface. You also configured the Toolsfile to create a custom tool layout. You learned how to manipulate RadEditor using client-side code including how to reference the editor, the document and the current selection, as well as responding to editor client events. Finally, you learned some of the editor's customization possibilities, how to optimize RadEditor for multiple instances and how to localize RadEditor for a specific language.
580
21.1 Objectives
Explore features of the RadButton control. Getting Started Use RadButton with external orembedded icons RadButton as an Image Button RadButton as a toggle button.Learn howto implement, radios, checkboxes anda three state checkbox. Explore the most important properties of RadButton. Creating a single click button. Creating bigger icons and buttons Confirm postback with RadButton
21.2 Introduction
The RadButton control provides the features, that ASP.NET Button, ImageButton, LinkButton, RadioButton and CheckBox controls have. The control can be easily styled by changing the Skin property, and alternatively setting properties that change the look of the control. This will eliminate the need to use the RadFormDecorator, just to style a single button. Developers can easily migrate their applications from using the standard ASP.NET (button) controls to the new RadButton control, because most of their functionality is provided by our control, and is controlled by the same or similar(intuitive) properties. RadButton can be also configured to behave as a toggle buttonand rendered as a check box, a radio button or a completely customized toggle button with multiple states. You can make the control even more intuitive by placing an Icon right next to the text, by choosing from the predefined icons, or specifying your own.
581
582
583
RadButton provides an easy way to show different icon when the mouse is hovering over the control, or the button is pressed. This is achieved through the Icon.PrimaryHoveredIconUrl(SecondaryHoveredIconUrl) and Icon.PrimaryPressedIconUrl(SecondaryPressedIconUrl). At first the Icons might not be positioned the way we want, but this can be easily fixed by directly setting the properties that control the top, bottom, left or right edge of the respective icon. These are:
Additionally, a CSS class can be set to the icon, and the position configured using CSS. 1. Properties: <telerik:RadButton ID="RadButton2" runat="server" Text="Shopping Cart"> <Icon PrimaryIconUrl="~/img/Cart.png" PrimaryIconTop="4px" PrimaryIconLeft="5px" SecondaryIconUrl="~/img/Add.png" SecondaryIconTop="4px" SecondaryIconRight="5px"> </telerik:RadButton>
584
The full list of the classes can be found on our online demos (http://demos.telerik.com/aspnetajax/button/examples/embeddedicons/defaultcs.aspx) site: Note: The CssClass are composed in the following way: [r]ad[b]utton[Iconname] == rbAdd
585
RadButton with background image, icons and text. There are two ways to display an image on the control: 1. The first and the easiest way is to set the Image.ImageUrl property to the location of the image used. Setting the IsBackgroundImage to true enables the developer to use the image as background, and set text and icons to his/her button. ASPX <telerik:RadButton ID="ImageButton1" runat="server" Width="37px" Height="36px" Text="Download"> <Image ImageUrl="~/img/cb_download.png" /> </telerik:RadButton> 2. The second way to set the image using RadButton's CssClass property. Basically we set the backgroundimage in the CssClass, and enable the image button functionality by setting Image.EnableImageButton=true. This approach is preferred when you want to use an image sprite for the button (see sample below). You set the background-image and background-position in the CssClass, and then in the HoveredCssClass and PressedCssClass, only the background-position of the hovered and pressed image. If the user wants she/he can display a different image when the mouse is hovering over the control, or the button is pressed using the HoveredImageUrl and PressedImageUrl properties respectively.
586
CheckBoxes:
ASPX <telerik:RadButton ID="btnToggle1" runat="server" Text="Checkbox 1" ToggleType="CheckBox" ButtonType="StandardButton"></telerik:RadButton> <telerik:RadButton ID="btnToggle2" runat="server" Text="Checkbox 2" ToggleType="CheckBox"
587
Checked state:
Radios:
ASPX <telerik:RadButton ID="btnToggle4" runat="server" Text="Radio Button 1" ToggleType="Radio" ButtonType="StandardButton"></telerik:RadButton> <telerik:RadButton ID="btnToggle5" runat="server" Text="Radio Button 2" ToggleType="Radio" ButtonType="LinkButton"></telerik:RadButton> <telerik:RadButton ID="btnToggle6" runat="server" Text="Radio BUtton 3" ToggleType="Radio" ButtonType="ToggleButton"></telerik:RadButton>
Checked state:
If a Radio ToggleType mode is chosen, the developer could also set the GroupName property, which specifies the name of the group that the radio button belongs to. Use this property to specify a grouping of radio buttons to create a mutually exclusive set of controls.
CustomToggle buttons:
588
Filled State:
Checked State:
589
The user is free to specify as many toggle states as needed, and can completely change the look of the control using the different RadButtonToggleState properties. In the code above, the PrimaryIconCssClass property is used to specify a three-state (3-state) checkbox, and the Text property to have different text depending on the currently selected state. To take a closer look at RadButton's "toggle button" functionality please visit our online demos (http://demos.telerik.com/aspnet-ajax/button/examples/togglebutton/defaultcs.aspx).
Text - specifies the text displayed in the RadButton control. AutoPostBack - specifies a bool value indicating whether the control will automatically post the page back to the server. CausesValidation - specifies a bool value indicating whether validation is performed when the RadButton is clicked. ButtonType - specifies the type of the button. The following types exist:
StandardButton (default) LinkButton ToggleButton Each ButtonType provides certain functionality that is unique. More information on the features of different button types can be found in each button category.
CommandName - specifies the group of controls for which the RadButton control causes validation when it posts back to the server.
PrimaryIconUrl -specifies the URL to the image used as Primary Icon. PrimaryIconCssClass -specifies the CSS class applied to the Primary icon. SecondaryIconUrl - specifies the URL to the image used as Secondary Icon. SecondaryIconCssClass -specifies the CSS class applied to the Secondary icon.
IsBackgroundImage - specifies a bool value indicating how the image is used - i.e. as a background image
590
ImageUrl-specifies the URL to the image used as button. HoveredImageUrl-specifies the URL to the image showed when the RadButton is hovered. PressedImageUrl- specifies the URL to the image showed when the RadButton is pressed. EnableImageButton- specifiesa bool value indicating whether the RadButton is rendered as Image Button.
SplitButtonspecific properties:
EnableSplitButton -specifies a bool value that indicates whether the SplitButton functionality will be enabled SplitButtonPosition -specifiesthe position where the SplitButton will appear, relatively to the main button (Left or Right). Position:
UseSubmitBehavior -gets or sets a bool value indicating whether the RadButton control uses the client browser's submit mechanism or the ASP.NET postback mechanism.
NavigateUrl - specifies the URL of the page to navigate to, without posting the page back to the server. When this property is sets, the button is rendered as an <a/> (anchor) element. Target- specifiesthe target window or frame in which to display the Web page content linked to when the RadButton control is clicked.
ToggleType - specifies the type of the Toggle Button. There are three toggle types:
GroupName -Valid when ToggleType: Radio. Gets or sets the name of the group that the radio button belongs to. Checked- specifies a bool value indicating whether the RadButton control is checked. In the case when the ToggleButton has more than 2(two) states, the control is not checked in the case when the current state of the RadButton is the First state, in all other cases it is Checked. Direction- specifies the direction in which the states will be switched, when more than two ToggleStates are specified. Directions:
591
SelectedToggleState - specifies the current state of the RadButton. SelectedToggleStateIndex- specifiesthe index of the currently selected ToggleState of the RadButton control, when used as a custom toggle button. ToggleStates -Collection of RadButtonToggleState. The different states are controlled through a collection of states. The collection can contain, maximum of four states. The order of switching the states is determined by the 0-based position index at which the state occurs in the collection. So, the first item in the ToggleStates, is the first state, the second item is the second state, and so on. When the ToggleType is Radio or CheckBox, the first item (state) of the ToggleStates is used as the alternate state of the RadButton.
Text - specifies the text displayed in the RadButton control. Height -Selected- Gets or sets a bool value indicating whether the ToggleState is selected or not. CssClass-
592
593
RadButton with radconfirm (requires RadWindowManager on the page): RadButton with radconfirm <script type="text/javascript"> function RadConfirm(sender, args) { var callBackFunction = Function.createDelegate(sender, function (shouldSubmit) { if (shouldSubmit) { this.click(); } }); var text = "Are you sure you want to submit the page?"; radconfirm(text, callBackFunction, 300, 100, null, "RadConfirm"); args.set_cancel(true); } </script> <telerik:RadButton ID="btnRadConfirm" runat="server" Text="RadConfirm" OnClientClicking="RadConfirm"> </telerik:RadButton> <telerik:RadWindowManager ID="windowManager1" runat="server"> </telerik:RadWindowManager> RadButton with RadWindow. Using RadWindow as the confirmation window gives the developer the ability to fully customize the look and feel of the dialog. RadButton with RadWindow <script type="text/javascript"> function CustomRadWindowConfirm(sender, args) { $find("<%=confirmWindow.ClientID %>").show(); $find("<%=btnYes.ClientID %>").focus(); args.set_cancel(true); } function YesOrNoClicked(sender, args)
594
595
22.1 Objectives
Learn what Binary Image is. Where it can be used and how to bound data to it. Review which are the most important properties of the RadBinaryImagecontrol.
22.2 Introduction
The Binary Image control is used for showing an image stored as binary data in a database. The control can be used in any data bound control (RadGrid, Repeater, DataList, GridView, etc.). The control uses an internal http handler which streams the image from the binary source to the page in which it has to be visualized. The storage of the binary stream when transferred between the control itself and the handler is the HttpContext.Current.Cache object and the image is cached in the browser. Its default expiration time is 2 hours (unless the control in which the RadBinaryImage is nested is rebound or recreated). In case the browser cache is disabled, the image will be persisted for 2 minutes on the server before it is streamed to the page from the data source. You need to register the http handler of the RadBinaryImage control either using its Smart Tag or manually in the web.config file to ensure that it will be served as expected when the page is rendered. [Web.config] Classic mode <httpHandlers> <remove path="*.asmx" verb="*" /> ... <add path="Telerik.Web.UI.WebResource.axd" type="Telerik.Web.UI.WebResource" verb="*" validate="false" /> </httpHandlers> [Web.config] Integrated mode <system.webServer> ... <handlers> <add name="Telerik_Web_UI_WebResource_axd" verb="*" preCondition="integratedMode" path="Telerik.Web.UI.WebResource.axd" type="Telerik.Web.UI.WebResource" /> </handlers> </system.webServer> The most important properties of the RadBinaryImage control are presented below:
DataValue: Property which specifies the source field from which the data will be passed as a byte array. Height: Specifies the height of the binary image. Width: Specifies the width of the binary image. AlternateText: The text that will replace the image when it is not available/cannot be streamed. ToolTip: The text that will be displayed in a browser tooltip when you hover the image. AutoAdjustImageControlSize: Scales the image based on explicitly set width/height dimensions to avoid stretch or blur effect when its original dimensions do not fit. The default value is true. HttpHandlerUrl: Can be used to specify the location of a custom http handler which extends the default
596
ImageUrl: Applicable when no DataValue is specified to gracefully degrade to regular ASP.NET Image mode. When null value is returned from the source, the ImageUrl property can be used to specify default image for RadBinaryImage. ImageAlign: Specifies the image alignment inside its container. ResizeMode: Specifies whether the image should be sized automatically if width and height of the image are set in pixels. Possible values are:
Crop (the image will be trimmed) Fit (the image will be sized to fit the given dimensions) None (default)
SavedImageName: Sets images filename which will appear inside SaveAs browser dialog if image is saved
597
598
23.1 Objectives
Explore the features of RadFilter control Learn how to define filter expressions manually Learn how to use RadFilterin conjunction withRadGrid and RadListView Explore the client-side and server-side events
23.2 Introduction
The purpose of RadFilter control is to allow the developer to supply an interface for constructing strongly typed filter expressions. These expressions can be used to: - query data from a data source control - supply filter expressions to controls that support such expressions, for example RadListView and RadGrid Most of the RadFilter control functionalities require that the ViewState is enabled - both for the control, and any container controls, in order for the operations to be handled properly and the filter expressions persisted.
Constructingfilter expressions
It is possible to manually construct filter expressions and add them to RadFilter afterwards. This is demonstrated in the code-snippet below: [C#] if (!IsPostBack) {
599
Client-side events
OnFilterCreated - fires whenthe filter control is created OnFilterCreating - RadFilter rises this event when the control is being created but the process is not yet completed OnFilterDestroying - this event fires when the filter control is being destroyed on the client
23.5 Summary
So far we discussed the most important features of RadFilter. We learned how to use the control in conjunction with RadGrid and RadListView. The topic also covered the custom expressions as well astheevents (both client-side and server-side).You can examine the RadControls for ASP.NET AJAX section in our website for more information (and demos)about the control.
600
24.1 Objectives
Getting familiar with RadImageEditor control and its features Explore the design time interface - Smart Tag and Properties Window Learn how to utilize the RadImageEditors rich client-side API Learn how to use a ToolsFile or the Tools inner tag to configure the toolbar Learn how to use the server-side events to manipulate images from alternative source (database)
24.2 Introduction
RadImageEditor is a powerful and flexible graphics editing component that allows the users to modify their images directly in the browser, without installing any third party plugins. The actions on the image are performed on the client or, through a light callback, on the server, giving you the ability to perform the editing quickly and see the changes on the fly. The control is fully customizable, intuitive to work with and provides many features. Here are some the key ones:
Rich Client-side functionality - RadImageEditor exposes many of the methods used to perform the operations on the image, so that the image can be easily modified programmatically. Customizable Tools - The developer has full control over the ImageEditor's set of tools. The ToolsFile property or the Tools collection can be used to specify the desired buttons that will appear in the ToolBar. Intuitive Dialogs - RadImageEditor provides a set of built-in dialog controls that are easy to use and offer the user a quick and intuitive way of modifying the images in the desired fashion. Integrated RadControls - We have embedded some of our ASP.NET Ajax RadControls into the ImageEditor to benefit from their rich functionality. This not only makes the new component feature rich, but a perfect example of how the RadControls work together in complex scenarios. The integrated controls are loaded on demand thus ensuring optimal loading speed and scalability. Undo/Redo Actions - RadImageEditor saves all the operations, so each change performed on the image can be reverted or re-applied again. The operations stack is cleared on postbacks, because we assume the user won't initiate a postback unless she is finished with the editing. Image Operations - A variety of operations can be performed on a given image. This includes rotation, resizing, changing the transparency, cropping and many more.
add the Telerik WebResource handler - if it is not present in the web.config you are presented with an option to add it add the needed AJAX resources to the web application - ScriptManager or RadScriptManager, RadAjaxManager, RadStyleSheetManager change the Skin of the control via the dedicated dropdown quickly get help via our online learning center online help, examples, knowledge base and code library, web search and our support center
601
602
603
The Tools inner tag allows you to set the tools you wish to use in the markup of the control. This is more difficult to maintain than an xml source, yet allows for a nice exception of the common feel if you need one: Setting the inner Tools tag <telerik:RadImageEditor ID="RadImageEditor1" runat="server" ImageUrl="> <Tools> <telerik:ImageEditorToolGroup> <telerik:ImageEditorTool CommandName="Save" /> <telerik:ImageEditorToolSeparator /> <telerik:ImageEditorToolStrip CommandName="Undo" Text="Undo" /> <telerik:ImageEditorToolStrip CommandName="Redo" Text="Redo" /> <telerik:ImageEditorToolSeparator /> <telerik:ImageEditorTool CommandName="Crop" /> <telerik:ImageEditorTool CommandName="Opacity" /> </telerik:ImageEditorToolGroup> </Tools> </telerik:RadImageEditor> This declaration will give the following:
604
If either one of these options is used the default toolbar is overridden by the new declaration. If both are used i.e. you declare Tools in the markup and point the ToolsFile property to a valid source you will get both toolbars in the rendered RadImageEditor first the ones from the xml, then the ones from the markup:
24.6 Localization
RadImageEditor is fully localized by using Global resources. The control comes with three built-in language packs, English, German and French and you can easily switch by setting the Language property of the control or setting UICulture property to the @Page. The Language property is with higher priority than the global UICulture setting. There are two options to localize the RadImageEditor by using resource files and by using the Localization property of the control. You can use *.resx files to localize (or customize) the controls localization strings with minimum efforts. The RadControls installation wizard copies the built-in resource files in the App_GlobalResources folder in your local installation. You can either create your own language pack or use an existing one (if available for your language). The following steps demonstrate how to create a new language pack for RadImageEditor. 1. Add App_GlobalResources folder to the application folder (if it does not already exist) 2. Copy RadImageEditor.Main.resx and RadImageEditor.Dialogs.resx files to App_GlobalResources folder 3. Create new copies of the above files and name them according to the new languages culture. RadImageEditor.Main.[your_language].resx and RadImageEditorDialogs.[your_language].resx. Please note that you need to keep the original files in the folder as well 4. Open the newly copied language specific resource file and modify the keys values, but you should not modify/remove the ReservedResource key 5. Set the RadImageEditors Language property to the corresponding language 6. When you run the application, the new resources will be recognized and the corresponding hints or other UI elements will display in the new language The Localization property can be set in the code-behind and allows for easy minor adjustments on a small scale, for example: Localization Property C# RadImageEditor1.Localization.Main.AddText = "; RadImageEditor1.Localization.Main.Opacity = "; Localization Property VB.NET RadImageEditor1.Localization.Main.AddText = " "
605
606
607
608
609
610
25.1 Objectives
Explore the features of the RadListView control. Explore the RadListView design time interface, including Smart Tag and Properties View. Create simple application for binding data using the RadListView predefined layouts and the most common features. Learn how to perform manual CRUD (create, read, update and delete) operations through the RadListView server-side API. Explore the RadDataPager control and see how you can use it for paging navigation.
25.2 Introduction
RadListView is data-bound control and you can use it in any web application where you want to display data in a custom manner with uniquelook and feel. RadListView:
Provided the following templates: LayoutTemplate, ItemTemplate, AlternatingItemTemplate, EditItemTemplate, InsertItemTemplate, EmptyDataTemplate, ItemSeparatorTemplate, SelectedItemTemplate, GroupTemplate, GroupSeparatorTemplate, EmptyItemTemplate for customizing the RadListView layout.
Supports paging navigation either using built-in commands or RadDataPager/DataPager control. Hasrich server-side API for filtering items. Supports sorting and items selection. ListView-like grouping can be achieved with RadListView. For that purpose the GroupTemplate, GroupSeparatorTemplate and EmptyItemTemplate should be defined. RadListView offers the Items Drag & Drop capability, allowing you to easily implement scenarios that require dragging and moving data items on the page.
RadListView Templates
611
LayoutTemplate - It helps you define the overall appearance of the control, the outer wrapper that will be used for the listview rendering as well as the holder of its content. Note that you have to specify ItemPlaceholderID property value for RadListView that matches the id of an ASP.NET server control (with id and runat="server" properties set) which will be used as a holder of the actual listview data content. ASPX <telerik:RadListView ID="RadListView1" runat="server" ItemPlaceholderID="itemPlaceholder"> <LayoutTemplate> <fieldset> <legend>Items</legend> <asp:PlaceHolder ID="itemPlaceholder" runat="server" /> </fieldset> </LayoutTemplate> </telerik:RadListView>
ItemTemplate and AlternatingItemTemplate - These templates mark out how the data that is bound to the listview will be visualized in its odd/even items respectively. Since those are templates, you are free to customize their layout according to your custom conventions. EmptyDataTemplate - The content of the EmptyDataTemplate is displayed when no data is available in the RadListView data source. ItemSeparatorTemplate - Define the ItemSeparatorTemplate by adding there the html content which would display between the different items in the RadListView control. EditItemTemplate - Determines how and what controls will be rendered when an item is in edit mode. InsertItemTemplate - As the above one, determines how and what controls will be rendered in the RadListView insert form. SelectedItemTemplate - Defines here the contentsthat representsthe selected item in a RadListView. GroupTemplate - Create the group structure and look by defining the GroupTemplate. GroupSeparatorTemplate -Define this template to separate the different groups in a RadListView. EmptyItemTemplate - The EmptyItemTemplate content is displayed in place of the missing items for a group. For instance of the a group should contain 8 items but only 7 are available in database, the EmptyItemTemplate will be used for the eighth item of the group.
Paging
RadListView has native paging support. To enable paging, set the AllowPaging property to true. If you choose to use the integrated paging, you can add commandcontrols(Button, LinkButton, ImageButton) with a CommandName value of Page.In this case you also need to set the CommandArgument property of the command buttons.The possible values for it are: Next, Prev, FirstandLast. Thus yourpager buttons would allow the user to navigate to the next, previous, first and last page. Another page command you might want to use is the ChangePageSize command. It is should be set as CommandName of a button which will change the page of the RadListView. Here the CommandArgument of the button should be the new page size value. A simple pager might look as below: ASPX <telerik:RadListView ID="RadListView1" runat="server" ItemPlaceholderID="itemPlaceholder" AllowPaging="true"> <LayoutTemplate> <fieldset> <legend>Items</legend> <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
612
Sorting
Implementing sorting is quite easy with RadListView. All you need to do is to add SortExpression to its SortExpressions collection. You can do it either declaratively, so the RadListView data is sorted all the time, or do it dynamically on particular user action. Let's say we have a sort button which after clicked will sort the listview by a field descending. Then the Click event handler of the button would look like this: C# protected void SortButton_Click(object sender, EventArgs e) { RadListViewSortExpression expression = new RadListViewSortExpression(); RadListView1.SortExpressions.Clear(); expression.FieldName = "myFieldName"; expression.SortOrder = RadListViewSortOrder.Descending; RadListView1.SortExpressions.AddSortExpression(expression); RadListView1.Rebind(); } VB.NET Protected Sub SortButton_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim expression As New RadListViewSortExpression()
613
Filtering
RadListView provided rich server-side API for creating and applying filter expressions. It gives you the ability to filter the data displayed in a RadListView control without creating complex database queries.For more information on how to operate with it, you can refer to the documentation of the RaddListView for ASP.NET AJAX control.
Grouping
RadListView supports ListView-like grouping for its items. You can easily achieve displaying ofdata in groups with RadListView by setting the properties: GroupItemCount, GroupPlaceHolderID, ItemPlaceHolderID. In addition you need to define the following Templates: LayoutTemplate, GroupTemplate, GroupSeparatorTemplate, EmptyItemTemplate. Thus the skeletonfor a RadListView which displays its data in groups will be: ASPX <telerik:RadListView ID="RadListView1" runat="server" ItemPlaceholderID="itemPlaceholder" GroupPlaceholderID="groupsPlaceholder" GroupItemCount="4"> <LayoutTemplate> <asp:PlaceHolder ID="groupsPlaceholder" runat="server" /> </LayoutTemplate> <GroupTemplate> <fieldset style="float: left; width: 330px;"> <legend>Items group</legend> <table> <tr> <td> <asp:PlaceHolder ID="itemPlaceholder" runat="server" /> </td> </tr> </table> </fieldset> </GroupTemplate> <GroupSeparatorTemplate> <hr /> </GroupSeparatorTemplate> <EmptyItemTemplate> <div style="float: left; width: 160px; height: 120px"> <img src="Img/EmtpyItemImage.jpg" width="120px" height="150px" alt="No Employee to display" title="No Employee to display" /> </div> </EmptyItemTemplate>
614
Selecting
The selected items are accessible through the SelectedItems collection that consist of RadListViewDataItem objects. By default you can select only one item at a time. Multiple selection is possible if enabled via the AllowMultiItemSelection property. There are several ways to select/deselect an item in RadListView:
use the Selected property of RadListViewDataItem fire Select/Deselect command add/remove item's index to the SelectedIndexes collection
The selected items can be cleared using the ClearSelectedItems method. For detailed information on RadListView items selection feature, see the control documentation and online demos.
615
It also provides useful links that allow you to easily Ajaxify the control and optimize the web page that the grid appears on.
Layout Editor
Once you have selected Data Source for the RadListView the Open Layout Editor link appears in the Smart Tag.
616
Use to build the RadListView by choosing any of the predefined layouts, select Skin for the control or enable the most commonly used features.
Properties Window
Use the Properties window to manipulate the RadListView properties or to auto-generate server-side event
617
618
619
620
621
622
623
624
625
626
You can find the complete source for this project at: \VS Projects\ListView\ManualCRUDOperations
25.6 RadDataPager
Use RadDataPager to display paging navigation controls for other data-bound controls that implement the IPageableItemContainer or IRadPageableItemContainer interface (like the RadListView and MS ListView). You can easily add the RadDataPager control to a Web Form within Visual Studio. The paging interface appears wherever you place the RadDataPager control on the page. You may place it before or after the RadListView control, as well as within its LayoutTemplate element.
To use the RadDataPager control in its default state you can refer to the following properties:
PagedControlID is the ID of the control that implements one of the following interfaces IPageableItemContainer or IRadPageableItemContainer. This is the control that will be paged by RadDataPager control. If RadDataPager is placed in Controls collection of IPageableItemContainer / IRadPageableItemContainer setting this property is optional. In case PagedControlID is not set RadDataPager will attempt to find its container automatically. PageSize is the number of items and rows to display on each page. StartRowIndex gets the index of the first record that is displayed on a page of data. TotalRowCount gets the total number of records that are displayed in the underlying data source. MaximumRows gets the maximum number of records that are displayed for each page of data.
The RadDataPager fields lets you choose the controls that will appear in the pager field to help users navigate through the pages. To specify the pager fields, list the desired field elements between the opening and closing <Fields> tag inside the RadDataPager control. The RadDataPager built-in fields are: RadDataPagerButtonField, RadDataPagerPageSizeField, RadDataPagerSliderField, RadDataPagerGoToPageField and RadDataPagerTemplatePageField. You can use one or more pager field objects in a single RadDataPager control. For example when RadDataPager contains a RadDataPagerButtonField you have the ability to add arrow buttons for navigation to Next/Previous/First/Last page, link buttons with page numbers or both. ASPX <telerik:RadDataPager ID="RadDataPager1" PagedControlID="RadListView1" PageSize="2"
627
628
25.7 Summary
In this chapter we looked at the RadListView control and explored its most commonly used features like paging, sorting , filtering, grouping,items selection and drag and drop. Learned how to use RadListView in Design Time and build its layoutwith ease. You saw how toimplement a sample project on how to manipulate the data with RadListView. Finally, we described the RadDataPager control and how to use it for paging navigation in data-bound controls.
629
26.1 Objectives
Explore the main features of the RadNotification control Getting started by running a simple example Review the most important properties and how they are used together to control the RadNotifications behavior Review the basic ways to populate content in the notification Examine the extra built-in functionality context menus and icons See the use of a lightweight callback to update the content Examine a real-life scenario where the user is updated about a server-side event occurring
26.2 Introduction
The RadNotification is a very light control which can be used to display a notification message both from the server and the client. The notification is completely customizable, can be loaded on demand through a callback or WebService, can be automatically displayed and/or updated at specific intervals and supports different animation effects and at different position. Its most notable features are:
Semantic rendering - no HTML tables used Load on Demand through callback or WebService Built-in, fully customizable context menu Can contain simple text, HTML content and ASP.NET controls Automatically calculates position relative to the screen Automatic updates at a specified interval Automatic show at a specified interval Keep on mouse over AutoClose Delay Animation effects Content scrolling Advanced Skinning
630
TitleBar: This is the title of the notification. TitleIcon: The small image (16x16 pixels) shown in the titlebar. Menu Icon: The button used to show the title menu. It appears only if the ShowTitleMenu property is set to true. Close Button: The button used to close the notification. It appears only if the ShowCloseButton property is set to true. ContentIcon: The image (32x32 pixels) shown in the content area of the notification. Content or Text: This is the main part of the control. It can be customized using Text property or by declaring content between the RadNotification's ContentTemplate tags in ASP.NET.
631
You can use the RadNotifications SmartTag to add the needed AJAX resources to the web application (ScriptManager or RadScriptManager, RadAjaxManager, RadStyleSheetManager) or edit the content template of the RadNotification in the Design-time mode of the Visual Studio:
632
633
634
635
636
637
Use the Position, OffetX, OffsetY properties to control the position in which the notification is shown Use the Animation, AnimationDuration properties to control the way in which the notification is initially shown Use the ContentScrolling property to customize the availability of scrollbars. Possible values are Auto, None X, Y and Both. This requires the content to have explicit dimensions set in pixels to work correctly Use the ShowCloseButton, ShowTitleMenu, VisibleTitlebar, TitleIcon properties to control the behavior of the titlebar Use the AutoCloseDelay, KeepOnMouseOver, ShowInterval properties to control the time, after which the notification will automatically show/hide Use the LoadContentOn, UpdateInterval, ShowInterval properties to control when new content is loaded. They are most often used in a more advanced scenario when a CallBack is used to fetch the content Use the Text, Title, ContentIcon, WebMethodName, WebMethodpath, OnCallbackUpdate properties to control how the content is loaded. For more information refer to the Populating Plain Text and Rich Content (Section 26.7) section You can declare a custom menu between the NotificationMenu tags You can change the overall look and feel of the notification by changing its skin via the Skin, EnableShadow, EnableRoundedCorners properties.
The Position property gets/sets the top/left position of the notification relative to the browser. Its value is an enumerator with the following options: TopLeft, TopCenter, TopRight, MiddleLeft, Center, MiddleRight, BottomLeft, BottomCenter, BottomRight. The default is BottomRight. OffetX and OffsetY are used for fine-tuning the horizontal and vertical offset from the designated Position. Their values are set in pixels. The Animation property is used to get/set the animation effect of the notification. It is also an enumerator with the following options: None, Resize, Fade, Slide, FlyIn. The default is None. The TitleIcon and ContentIcon are used to set the icons that are shown in the notification. Set them to an empty string to disable the icon. For more information see the Embedded Icons (Section 26.5) article. The NotificationMenu and the ContentTemplate inner tags are used to declare the built in context menu and rich content respectively. For more information see the Notification Menu (Section 26.4) and Populating Plain
638
639
640
27.1 Objectives
Learn about the benefits of RadCompression Learn how to configure the RadCompression module
27.2 Introduction
RadCompression is a HttpModule that is designed to automatically compress your AJAX and Web Service responses. It will intercept the bits that your server is sending back to a browser (or Silverlight-client, for that matter) and compress them. Once the compressedresponse reaches the browser, standard browser technology takes-over and decompresses the response. The compression process is completely transparent to your clientside (JavaScript or Silverlight) and server-side code. It simply reduces the number of bits that must be sentfrom your server to your client and thus itimproves your page performance. RadCompression is not designed to be a complete replacement for the other HTTP compression tools, such as the built-in HTTP Compression in IIS 7. Instead, it is designed to work with those existing tools to cover scenarios they usually miss - namely the compressionof the responses of AJAX requests. If you have HTTP Compression enabled in IIS7, you'll discover that it does not compress your AJAX and Web Service responses; it only compresses the initial bits sent to the browser when the page is requested. By adding RadCompression to your project, you cover those gaps and start compressing your XHR (XmlHttpRequest). So, if RadCompression does not cover all HTTP traffic, what does it cover? RadCompression will automatically detect and compress requests that expect these content response types (as found in the HTTP request's "ContentType" header or "AcceptsTypes" header):
641
Postback compression
You can enable the postback compression by setting the enablePostbackCompression property of the RadCompression module to true (the default value is false). This can be done at application level in the following manner: [web.config] <configSections> ... <sectionGroup name="telerik.web.ui"> <section name="radCompression" type="Telerik.Web.UI.RadCompressionConfigurationSection, Telerik.Web.UI, PublicKeyToken=121fae78165ba3d4" allowDefinition="MachineToApplication" requirePermission="false"/> </sectionGroup> ... </configSections> <telerik.web.ui> <radCompression enablePostbackCompression="true"/> </telerik.web.ui>
27.4 Summary
642
643
28.1 Objectives
Explore features of the RadCaptcha control. Learn how to configure RadCaptcha for the runtime environment. Explore the RadCaptcha design time interface including the Smart Tag and major property groups. Learn how to configuring RadCaptcha for maximum security Configure RadCaptcha audio
28.2 Introduction
Telerik RadCaptcha is UI control that provides two major strategies for protection against automated form submissions:
Image with Modified Symbols (Captcha Image) - They are displayed in a form, and the user is required to input the symbols in a textbox. The Image is generated with an HttpHandler. Automatic Robots Discovery - this strategy uses predefined rules which decide whether the input comes from a robot or not. At this point, there are two implemented rules that could be applied either separately or simultaneously.
Minimum form submission time - the presumption is that a human cannot input the fields in a form correctly for a time less than 3 seconds (this is set by default, and could be modified). If the submission is executed faster than the predefined value, it is assumed that the executor is a robot. Invisible textbox in the form (the so-called "honeypot") - this rule requires the insertion of a textbox which is not visible when the form is styled. Still, it will be detected by a robot, and therefore if any data is entered, the executor is considered to be a robot.
Key features:
Three Modes for Protection - you can easily define which strategies to be used for spam protection. These
644
Set Custom Error Message - the error message that is displayed when the condition being validated fails. Simply set the ErrorMessage property of the RadCaptcha and the value will be displayed if the page is not valid. Background and Line Noise Level of the Captcha Image - you can easily control the background and the line noise of the Image by setting the respective value (None, Low, Medium, High or Extreme). The default value of the background and line noise level is Low. Font Family and Font Warp of the Captcha Image - you can easily choose which font family to be used for the Image text. Courier New is used as a default value for the font family. Furthermore, the amount of random font warping to apply to the rendered text can be changed by setting the FontWarp property of the CaptchaImage. The default amount of font warping is Low. Text Length and Possible Characters of the Captcha Image - the default length of the text is 5 characters, and the characters could be either letters or either numeric characters. Alternatively, you can choose what kind of characters to be used (only letters or only numeric characters), and change the length of the text. Maximum Time Interval of the Captcha Image - the maximum number of minutes the Captcha Image will be cached and valid. Minimum Timeout - minimum number of seconds the form must be displayed before it is valid. If you're too fast, you must be a robot. This is set when Minimum form submission time mode is used for Spam Protection.
2. Open the RadCaptcha Smart Tag and select the Enable RadCaptcha httpHandler link. Click OK to close the confirmation dialog for the RadCaptcha handler.
645
The httpHandler can be also enabled by placing the following lines in the web.config file: web.config <httpHandlers> <add path="Telerik.Web.UI.WebResource.axd" type="Telerik.Web.UI.WebResource" verb="*" validate="false" /> </httpHandlers> <handlers> <add name="Telerik_Web_UI_WebResource_axd" verb="*" preCondition="integratedMode" path="Telerik.Web.UI.WebResource.axd" type="Telerik.Web.UI.WebResource" /> </handlers> 3. In the Properties Window for the RadCaptcha control set the following properties: 4. ErrorMessage = You have entered an invalid code. 5. ValidationGroup = SubmitGroup 6. In the Properties Window for the ValidationSummary control set the ValidationGroup property to the same value as in RadCaptcha (ValidationGroup="SubmitGroup"). Do the same for the Button control. Here is how the controls' declarations look after setting the above mentionedproperties: Setting Properties <telerik:RadCaptcha ID="RadCaptcha1" runat="server" ErrorMessage="You have entered an invalid code" ValidationGroup="SubmitGroup"></telerik:RadCaptcha> <asp:Button ID="Button1" runat="server" Text="Button" ValidationGroup="SubmitGroup" /> <asp:ValidationSummary ID="ValidationSummary1" ValidationGroup="SubmitGroup" runat="server" /> Press F5 to run the Application. RadCaptcha validates the input on a post back.
646
ErrorMessage - The error message text generated when the condition being validated fails. Display - Gets or sets display behavior of error message. The available modes are:
None (Validator content never displayed inline) Static (Validator content physically part of the page layout) Dynamic (Validator content dynamically added to the page when validation fails)
ValidatedTextBoxID - Gets or sets the ID of the textbox to be validated, when only the RadCaptcha image is rendered on the page. (To render only the CaptchaImage and use Custom TextBox for user input, the CaptchaImage-RenderImageOnly property has to be set to true. See the description of theRenderImageOnlyproperty below. ValidatedTextBox - Read-only. Gets the TextBox that is being validated by the RadCaptcha ValidationGroup - specifies which group of controls is validated on validation
EnableCaptchaAudio - Gets or sets the bool value indicating whether the CaptchaAudio will be enabled. When set to true a LinkButton is rendered that, when clicked, retrieves the audio code. Use the'.rcCaptchaAudioLink' selector to apply custom skinning to the LinkButton. UseAudioFiles - Gets or sets a bool value indicating whether the audio code will be generated by concatenation of the audio files from a given folder. AudioFilesPath - Gets or sets the path to the directory where the audio (.wav) files are located. The default path is ~/App_Data/RadCaptcha where tilde (~) represents the root of the web application. RenderImageOnly - Gets or sets bool value that indicates whether the RadCaptcha image will only be rendered on the page (without the CaptchaTextBox and Label). When set to true only the image is
647
ImageStorageLocation - Gets or sets the storage location for the CaptchaImage (see note below):
Cache Session
InvisibleTextBoxLabel-Gets or sets the hidden textbox strategy label text. MinTimeout -Gets or sets the minimum number of seconds form must be displayed before it is valid. If you're too fast, you must be a robot.
Here isa sample declaration for RadCaptcha using some of the properties above: RadCaptcha declaration <telerik:RadCaptcha ID="RadCaptcha1" runat="server" ErrorMessage="You have entered an invalid code" ValidationGroup="SubmitGroup"> <CaptchaImage EnableCaptchaAudio="true" UseAudioFiles="true" /> </telerik:RadCaptcha>
3. Use a Custom Character Set Many bots rely on encountering a predictable set of characters or words to accurately parse a websites CAPTCHA image. By using a custom character set (http://demos.telerik.com/aspnetajax/captcha/examples/characterset/defaultcs.aspx) with RadCaptcha that includes non-alphanumeric characters (like @, !, #, $), you can increase your odds of beating the bots. No visual CAPTCHA image is perfect, and with the modern trend of employing humans to beat CAPTCHAs (http://www.theregister.co.uk/2008/04/10/web_mail_throttled/), a CAPTCHA is a road bump at best. Still, they prevent the casual spam bot from infiltrating your site and protect your forms from the script kiddies. Telerik will continue to add improved security features to RadCaptcha in future releases, but by following these simple guidelines, you can confidently get the most value out of a CAPTCHA today that a CAPTCHA can provide.
648
6. Enable the CaptchaAudio feature by setting theEnableCaptchaAudio property of the inner <CaptchaImage> tagto true, e.g. Enable RadCaptcha Audio <telerik:RadCaptcha ID="RadCaptcha1" runat="server" ErrorMessage="Page not valid. The code you entered is not valid." ValidationGroup="SubmitGroup" > <CaptchaImage EnableCaptchaAudio="true" BackgroundColor="#609f0a" TextColor="White" BackgroundNoise="None" /> </telerik:RadCaptcha> Press F5 to run the Application. RadCaptcha validates the input on a post back.
649
650
29.1 Objectives
Learn aboutthe Callback and WebService update mechanisms and how to configure RadXmlHttpPanel. Supported Scenarios: Learn when and how to use RadXmlHttpPanel. KnownIssues
Callback - When a client callback is used, the server Page does not go through its whole lifecycle, but only a small part of it. The client state is not updated, and it is not sent back to the client-side. When Callbacks are used, a POST request is made from the client to the server, and the values of all FORM fields, such as hidden fields (including the view state field) are sent to the server. When the view state is large, this could mean increased overhead. On the other hand, no extra files are needed to use this mode (unlike when using a WebService). WebService - can be used to handle the data request of the RadXmlHttpPanel. The WebMethodPath and the WebMethodName properties should be set and the RadXmlHttpPanel automatically retrieves and loads the data. Similarly as in the Client Callback the client state is not affected. A web service requires a couple of extra files to set up, but it is the most efficient approach, as no data, other than the Value string is sent over from the client to the server.
651
652
Default.aspx.vb Protected Sub RadXmlHttpPanel1_ServiceRequest(sender As Object, e As Telerik.Web.UI.RadXmlHttpPanelEventArgs) Label1.Text = "Label updated by XmlHttpPanel callback at: " + DateTime.Now.ToString() 'access the callback value from the client on the server using the e.Value property Label1.Text += "<br/> The returned value fron the client's set_value() function is: <strong>" + e.Value + "</strong>" End Sub
WebService Configuration: 1. Add XmlHttpPanel and set EnableClientScriptEvaluation to true. 2. Right click on the WebSite to Add New Item and in the window opened choose "Web Service". Make sure the check-box "Place code in separate file" is checked. If you work in a Web Application scenario a WebService codebehind file will be created. 3. Open the newly created "Web Service" class in the App_Code folder of your application. 4. Uncomment the [System.Web.Script.Services.ScriptService] just above the class to enable the Web Service to be called from the XmlHttpPanel. 5. Create a method that returns a string and accepts a single parameter of type object. Mark the method as [WebMethod] i.e. [WebMethod] public string GetHTML(object context) { return "Content updated by XmlHttpPanel using WebService at: " + DateTime.Now.ToString(); } The string returned from this method is the actual HTML content that will be pasted within the XmlHttpPanel. 6. Set the WebMethodPath property to the Web Service (usually the .asmx file), and the WebMethodName to the method that will be called by the XmlHttpPanel (i.e. GetHTML). 7. Create an <input/> that will call set_value() method of the XmlHttpPanel Here is how the page with the XMLHttpPanel and theWebService codebehind fileshould look when accomplishing the steps above:
653
App_Code\WebService.cs using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Services;
/// <summary> /// Summary description for WebService /// </summary> [WebService(Namespace = "http://tempuri.org (http://tempuri.org/)/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. [System.Web.Script.Services.ScriptService] public class WebService : System.Web.Services.WebService { public WebService () { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod] public string GetHTML(object context) { Dictionary<string, object> dictiionary = context as Dictionary<string, object>; //The value passed to the XmlHttpPanel can be of type object object value = dictiionary["Value"]; string value1 = ((object[])(value))[0].ToString();
654
OnClientResponseEnding
The OnClientResponseEnding client-side event replaces the existing OnClientResponseEnd client-side event. Please note that although the OnClientResponseEnding should be used from now on, the OnClientResponseEnd is still present in the controls API so that any existing applications are not broken after an upgrade to a newer version of the control. The OnClientResponseEnding occurs before the data (content) is pasted into the RadXmlHttpPanel, after a partial update request has been initiated by the RadXmlHttpPanel set_value method. The event handler receives two parameters: 1. The instance of the RadXmlHttpPanel control firing the event. 2. An eventArgs parameter containing the following properties and methods: 3. set_cancel lets you prevent from loading the content inside the RadXmlHttpPanel and raising the OnClientResponseEnded client-side event. 4. get_cancel returns a boolean value indicating whether the RadXmlHttpPanels content update was canceled. 5. get_content() gets the HTML content rendered inside the RadXmlHttpPanel
655
656
OnClientResponseError
The OnClientResponseError occurs in the cases when an error (WebService or Callback error) occurs when the RadXmlHttpPanel tries to load certain content. The event handler receives two parameters: 1. The instance of the RadXmlHttpPanel control in which the error occured. 2. An eventArgs parameter containing the following properties and methods: 3. set_cancelErrorAlert lets you prevent from displaying the built-in error alert that notifies the user that an error has occurred, and gives the possibility to display a custom error message. 4. get_cancelErrorAlert returns a boolean value indicating whether the RadXmlHttpPanels displaying of the built-in error alert has been canceled. The following example demonstrates how the user can display: a custom content inside the RadXmlHttpPanel or a custom error message (alert), if an error has occurred while loading content inside the panel. The panel tries to load RadCalendar control, but an error will occur because the controls RegisterWithScriptManager property has not been set to false. ASPX <script type="text/javascript"> function LoadCalendar() { var panel = $find("RadXmlHttpPanel1"); panel.set_value(value); } function OnClientResponseError(panel, args) { alert("OnClientResponseError fired because an error occured"); args.set_cancelErrorAlert(true); var content = "<label style='color: Red;'>The Control could not be loaded because of an callback error!</label>"; panel.set_html(content); } </script> <input type="button" value="LoadRadCalendar" onclick="LoadCalendar()" /> <telerik:RadXmlHttpPanel ID="RadXmlHttpPanel1" runat="server"
657
Property
658
659
30.1 Objectives
Introduction Getting Started Learn how to bind RadTagCloud to DataSource Configuring RadTagClound items Generating TagCloud from External Sources
30.2 Introduction
Telerik RadTagCloud is a flexible UI component for categorization and weighted visualization of user-generated tags or related keywords. The user can easily customize the appearance of the control, choose the items that will appear in the cloud, sort the tags alphabetically or by weight, in ascending or descending order, and use various other configuration options.
Key Features:
Distribution - specifies how the font size will be distributed among the items. When set to Linear the font size is distributed linearly and in the case of Logarithmic the items are weighted logarithmically.Sorting specifies in what order the TagCloud items will be listed. By default they are not sorted. The user can choose to sort them alphabetically or based on their weight, in ascending or descending order. Possible values for this property are: NotSorted (default), AlphabeticAsc, AlphabeticDsc, WeightedAsc and WeightedDsc. Filtering Of The Items - Three properties control the filtering of the items: MinimalWeightAllowed, MaxNumberOfItems and TakeTopWeightedItems. MinimalWeightAllowed - specifies the lower bound for the item Weight. If the Weight of the item is smaller than this bound, the tag will not appear in the cloud. The default value is 0.0, which means the items will not be filtered. MaxNumberOfItems - specifies the maximal number of items that can (will) be shown in the cloud. If the TakeTopWeightedItems property is set to true, the items with the highest weight will be taken. The default value is 0, which means the items will not be filtered. MinFontSize and MaxFontSize - specify the range of the font size, the TagCloud items could have. The defualt values are 10px and 20px, respectively. These properties accept values of type System.Web.UI.WebControls.Unit and the font-size of the TagCloud items will have the same System.Web.UI.WebControls.UnitType as the one of the properties. The value of MaxFontSize must be greater or equal than the one of MinFontSize.
660
2. In the Source view of the .aspx page, find the definition of the TagCloud, and add the <Items></Items> inner property. 3. Between the opening and the closing tag of the <Items> property add the following list of items. Every item represents a country, with the Weight of the item equal representing the millions of people living there, and the NavigateUrl pointing to the country's Wikipedia article. Inner Items tags of RadTagCloud <Items> <telerik:RadTagCloudItem Text="Russia" Weight="141.9" NavigateUrl="http://en.wikipedia.org/wiki/Russia" /> <telerik:RadTagCloudItem Text="Nigeria" Weight="154.7" NavigateUrl="http://en.wikipedia.org/wiki/Nigeria" /> <telerik:RadTagCloudItem Text="Saudi Arabia" Weight="28.6" NavigateUrl="http://en.wikipedia.org/wiki/Saudi_Arabia" /> <telerik:RadTagCloudItem Text="Canada" Weight="34.1" NavigateUrl="http://en.wikipedia.org/wiki/Canada" /> <telerik:RadTagCloudItem Text="USA" Weight="309.4" NavigateUrl="http://en.wikipedia.org/wiki/USA" /> <telerik:RadTagCloudItem Text="Sweden" Weight="9.3" NavigateUrl="http://en.wikipedia.org/wiki/Sweden" /> <telerik:RadTagCloudItem Text="Germany" Weight="81.7" NavigateUrl="http://en.wikipedia.org/wiki/Germany" /> <telerik:RadTagCloudItem Text="Turkey" Weight="72.5" NavigateUrl="http://en.wikipedia.org/wiki/Turkey" /> <telerik:RadTagCloudItem Text="Japan" Weight="127.3" NavigateUrl="http://en.wikipedia.org/wiki/Japan" /> <telerik:RadTagCloudItem Text="France" Weight="65.4" NavigateUrl="http://en.wikipedia.org/wiki/France" /> </Items> 4. In the Properties Window of RadTagCloud set the following properties 1. Width="400px" 2. MaxFontSize="50px"
661
Distribution - type: enumerator - Gets or sets a value indicating how the font-size will be distributed among the different words (items). Values:
Linear - The font-size is linearly distributed among the different words based on their weight. Logarithmic - The font-size is logarithmically distributed among the different words based on their weight.
MinFontSize - type: Unit - Unit values - Gets or sets the font-size to the least important (frequent) item. MaxFontSize - type: Unit - Unit values - Gets or sets the font-size to the most important (frequent) item. MinimalWeightAllowed - type: Double - Gets or sets the minimal weight a TagCloud item could have. If the weight of the item is less than this value, the keyword will not appear in the cloud. The default value is 0.0, which means the items will appear in the cloud regardless of their weight. MaxNumberOfItems - type: Integer - Gets or sets the maximal number items that can appear in the cloud. The default value is 0, which means the items will appear in the cloud no matter their count. TakeTopWeightedItems - type: Boolean - Should be used with MaxNumberOfItems property. Gets or sets a bool value indicating whether the [MaxNumberOfItems] visible items will be the ones with the biggest weight, or the ones that occur first in the DataSource. The default value is false (i.e. the items are the first that appear in the DataSource). RenderItemWeight - type: Boolean - Gets or sets a bool value indicating whether the item weight will be rendered. It is rendered right next to the item's text. Sorting - type: enumerator - Gets or sets a value indicating how the TagCloud items will be sorted. Values:
662
NotSorted - The TagCloud items are left as they appear in the Items collection (DataSource). AlphabeticAsc -The TagCloud items are sorted alphabetically in ascending order. AlphabeticDsc -The TagCloud items are sorted alphabetically in descending order. WeightedAsc -The TagCloud items are sorted based on their Weight in ascending order. WeightedDsc - The TagCloud items are sorted based on their Weight in descending order.
Server-Side Events:
ItemDataBound - Adds or removes an event handler method from the ItemDataBound event. The event is fried right after RadTagCloudItem is databound. ItemClick - Adds or removes an event handler method from the ItemClick event. The event is fired after RadTagCloudItem is clicked.
RadTagCloudItem properties:
DataItem - type: object - Gets or sets the data object (from the data source) associated with the TagCloud item. NavigateUrl - type: string - Gets or sets the URL of the TagCloud item. Text - type: string - Gets or sets the text that is displayed in the TagCloud item. Weight - type: double - Gets or sets the weight, that determines how the TagCloud item (tag, keyword) will be styled. Greater value means, the value of the font size will be closer to the one of the RadTagCloud's MaxFontSize property.
30.5 Databinding
RadTagCloud supports binding to all ASP.NET DataSource components, including
To bind to a DataSource component, you need to set the following properties: 1. DataSource - Set to an instance of your data source. This is mandatory when binding the RadTagCloud at runtime. 2. DataSourceID - Set to the ID of your data source. This is mandatory when binding the RadTagCloud declaratively. 3. DataMember - If the data source is a DataSet and DataMember is set, then the RadTagCloud is bound to the DataTable with the respective name in the DataSet. If DataMember is not set, the TagCloud is bound to the first DataTable in the DataSet. 4. DataTextField - This is the field name from the data source that populates each item's Text property during binding.
663
664
665
the user can choose how the items will be listed in the cloud. The items can be sorted alphabetically or based on their weight, in ascending or descending order. Items can be filtered by setting either of the following properties:
MinimalWeightAllowed- specifies the lower bound for the item Weight. If the Weight of the item is smaller than this bound, the tag will not appear in the cloud. The default value is 0.0, which means the items will not be filtered. MaxNumberOfItems - specifies the maximal number of items that can (will) be shown in the cloud. If the TakeTopWeightedItems property is set to true, the items with the highest weight will be taken. The default value is 0, which means the items will not be filtered.
Note: Please note that, neither the filtering, nor the sorting, modifies the Items collection of the TagCloud,
666
Text - sets text value for direct input generation source TextFile - specifies the location of the file to be used as a generation source TextUrl - specifies the URL of the web site to be used as a generation source
If more than one of these properties are set RadTagCloud will combine the sources when generating the tags. In the example below, you can generate tags from a web site by setting an absolute URL in the input field: ASPX Enter a valid URL and press the Update button<br /> to populate the Tag Cloud control below:<br /><br /> <asp:TextBox ID="urlField" runat="server" TextMode="SingleLine" Width="285px" ToolTip="The URL must start with http://"></asp:TextBox> <asp:RegularExpressionValidator ID="urlValidator" runat="server" SetFocusOnError="true" ErrorMessage="Valid URL should start with http://" ControlToValidate="urlField" ValidationExpression="http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=] *)?"></asp:RegularExpressionValidator> <br /> <br /> <asp:Button ID="urlButton" runat="server" Text="Generate" OnClick="urlButton_Click" /> <br /> <br /> <telerik:RadTagCloud Text="Tag Cloud" ID="RadTagCloud1" runat="server" MaxNumberOfItems="30" TakeTopWeightedItems="true" PunctuationCharactersValid=".'#$ Width="200px"> </telerik:RadTagCloud> C# Codebehind protected void urlButton_Click(object sender, EventArgs e) { RadTagCloud1.TextUrl = urlField.Text; } VB.NET Codebehind Protected Sub urlButton_Click(sender As Object, e As EventArgs) RadTagCloud1.TextUrl = urlField.Text End Sub
667
31.1 Objectives
Explore features of the RadRating control. Learn how to configure RadRating. Explore the RadRating design time interface including the Smart Tag and major property groups. Learn some advance customizations Learn how to control RadRating using its client-side API.
31.2 Introduction
Telerik RadRating is a flexible UI component that allows users to intuitively rate by selecting number of items [stars] from a predefined maximum number of items. The user can fully customize the control by configuring its orientation, rating precision, direction etc. Key features:
Horizontal/Vertical Orientation - depending on your needs, RadRating can be displayed horizontally or vertically on the page by setting the Orientation property. Direction - you can configure the RadRating control to reverse its standard direction using its IsDirectionReversed property. The standard direction is from left to right (or from top to bottom if it has vertical orientation). Maximum Number of Items - by setting a value to the ItemCount property you can easily choose the maximum number of items the user can rate from. Selection Mode - it can be Single or Continuous. In Single mode a single item [star] is marked as selected and in Continuous mode all items, starting from the first one, are marked as selected. Rating Precision- the RadRating control enables the users to select their rating value precisely. By setting the Precision property to one of the following: Exact, Half, Item - you can rate by selecting: a precise part of the star [Exact], half a star [Half] or the whole star [Item].
668
You can specify the number of the rating items by setting value to ItemCount property Changing the voting direction from right to left is easily done by turning IsDirectionReversed property on If you want you can change the ratings precision to Item, Half-item or Exact using the Precision property In order to disable the rating and use it to display its current value you need to turn on the ReadOnly property Turning AutoPostBack property on will cause the RadRating control to trigger a postback when the user rate
Individual property settings such as BorderColor, BorderWidth, ForeColor, etc. These properties will workin limited scenarios where the styles or skins are not already at work and where you have a property that already addresses the visual change you need to make. Skins: You can set the Skin to an predefined value to get a coordinated look-and-feel. You can also customize an existing skin or build your own from scratch. Skins provide a generalized framework
Client-Side Events We will explore these events in the upcoming section on Client-Side Programming. For now, just know the events fire on the client when Rating is first loaded, and when the user rates.
669
ToolTip - the tooltip shown when the mouse pointer is hovered over the item. CssClass - the CSS class applied to the item. ImageUrl - the URL of the image displayed when item is not rated. SelectedImageUrl - the URL of the image displayed when the item is selected (rated). HoveredImageUrl - the URL of the image displayed when the item is not rated but the mouse pointer is over the item. HoveredSelectedImageUrl - the URL of the image displayed when the item is selected (rated) and the mouse pointer is over the item. ItemHeight(RadRating) - the height of every item. (The property is set to the RadRating control and not to the Item.) ItemWidth (RadRating) - the width of every item. (The property is set to the RadRating control and not to the Item.)
Server-side Events RadRating offers one server-side event Rate. This event can be used in combination with AutoPostBack=true, this way you can handle on the server when user has rated.
C# Declaring RadRating with custom Items server-side and assigning handler to the Rate event
protected void Page_Load(object sender, EventArgs e) { RadRating RadRating1 = new RadRating(); RadRating1.SelectionMode = RatingSelectionMode.Single; RadRating1.AutoPostBack = true; RadRating1.Rate += new EventHandler(RadRating1_Rate); RadRatingItem negativeVote = new RadRatingItem(); negativeVote.Value = -1; negativeVote.ImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/down.png"; negativeVote.HoveredImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/downh.png"; negativeVote.HoveredSelectedImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/downh.png"; negativeVote.SelectedImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/downh.png"; negativeVote.ToolTip = "No"; RadRating1.Items.Add(negativeVote); RadRatingItem emptyVote = new RadRatingItem(); emptyVote.Value = 0; emptyVote.ImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/0.png"; emptyVote.HoveredImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/0h.png";
670
VB Declaring RadRating with custom Items server-side and assigning handler to the Rate event
Protected Sub Page_Load(sender As Object, e As EventArgs) Dim RadRating1 As New RadRating() RadRating1.SelectionMode = RatingSelectionMode.[Single] RadRating1.AutoPostBack = True AddHandler RadRating1.Rate, AddressOf Me.RadRating1_Rate Dim negativeVote As New RadRatingItem() negativeVote.Value = -1 negativeVote.ImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/down.png" negativeVote.HoveredImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/downh.png" negativeVote.HoveredSelectedImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/downh.png" negativeVote.SelectedImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/downh.png" negativeVote.ToolTip = "No" RadRating1.Items.Add(negativeVote) Dim emptyVote As New RadRatingItem() emptyVote.Value = 0 emptyVote.ImageUrl = "http://demos.telerik.com/aspnetajax/rating/examples/itemscollection/Images/Rating2/0.png" emptyVote.HoveredImageUrl = "http://demos.telerik.com/aspnet-
671
672
31.6 Summary
In this chapter you looked at the RadRating control and saw some of the powerful features it provides. We explored the client-side and server-side properties of the control. Learn how to configure the control serverside or using Property window, demonstrated the server-side event Rate, configured the control to use custom items programmatically.
673
32.1 Objectives
Explore the basic structure of the RadRibbonBar control and learn more about the different items that the control holds. Learn how to create a simple RadRibbonBar control. Explore some of the client-side methods for working with the items collection and some of the client-side events. Explore the server-side methods for working with the items collection and some server-side events. Learn how to use the ItemTemplate of the RadRibbonBar control. Explore RibbonBars Image Rendering Mode and learn how to add correctly images to Buttons.
32.2 Introduction
The Telerik ASP.NET AJAX RibbonBar control allows you to easily organize the navigation of your application in a simple, structured way. The control includes enhanced navigation capabilities by elegantly grouping menu items in a RibbonBarMenu. The RibbonBarMenu along with the different types of buttons like SplitButtons and ToggleButtons are put into nicely styled groups. Furthermore, the content of these groups can easily be accessed simply by clicking on their tabs. The smartly designed layout allows each item to have various image sizes. Thus you can set the different images accordingly depending on its size. Below you can find the basic structure of the RadRibbonBar control:
674
The RibbonBarTab on its hand stays on the same level as the RibbonBarApplicationMenu with the slight difference that it should be placed (in the markup) in the RadRibbonBar control.
675
Finally the items are separated in RibbonBarGroups, which nicely form collections of similar tools. Here is a list of the items that can be placed in a RibbonBarGroup
RibbonBarButton - The most used control in every toolbox; RibbonBarSplitButton - A combination between menu and button; RibbonBarToggleButton - A button with toggle state; RibbonBarToggleList - List of ToggleButtons with at most one selected item at any time (similar to OptionButtonList); RibbonBarButtonStrip - A container for buttons with specific appearance; RibbonBarMenu - Light-weight menu designed specifically for the needs of RadRibbonBar; RibbonBarTemplateItem For anything else that you would be missing in the rich, but still finite toolbox of RadRibbonBar.
676
3. Add a RibbonBarTab to the RadRibbonBar control 4. Add a RibbonBarGroup inside the above mentioned RadRibbonTab. 5. Add any of the different buttons that you may need in the RibbonBarGroup ASPX <telerik:RadRibbonBar ID="RadRibbonBar1" runat="server" SelectedTabIndex="0"> <telerik:RibbonBarTab> <telerik:RibbonBarGroup Text="Group1" > <Items> <telerik:RibbonBarButton Text="New" /> <telerik:RibbonBarButton Text="Edit"/> </Items> </telerik:RibbonBarGroup> </telerik:RibbonBarTab> </telerik:RadRibbonBar>
FindButtonByValue returns a reference to a button given the value of its Value property. FindControl returns a reference to an item given the value of its ID. FindGroupByValue - returns a reference to a group given the value of its Value property. FindMenuItemByValue - returns a reference to a menu item given the value of its Value property. FindTabByValue - returns a reference to a tab given the value of its Value property. FindToggleButtonByValue - returns a reference to a toggle button given the value of its Value property.
677
ApplicationMenuItemClick - Occurs when an item of the Application Menu is clicked ButtonClick - Occurs when a Button is clicked ButtonToggle - Occurs when a Toggle Button is toggled LauncherClick - Occurs when a Group Launcher is clicked MenuItemClick - Occurs when a Menu Item is clicked. SelectedTabChange - Occurs when a non-selected Tab is clicked SplitButtonClick - Occurs when a Split Button or a button inside it is clicked. ToggleListToggle - Occurs when a Toggle Button in a Toggle List is toggled
findItemByText returns the first found item containing the specified text findTabByValue - returns a reference to a tab given the value of its Value property. findGroupByValue - returns a reference to a group given the value of its Value property. findButtonByValue returns a reference to a button given the value of its Value property. findToggleButtonByValue - returns a reference to a toggle button given the value of its Value property. findMenuItemByValue - returns a reference to a menu item given the value of its Value property.
Once you have located an item, you can use its properties to change its value, text, select it, disable it, delete it etc. You can find the complete source for this project at: \VS Projects\RibbonBar\DisableItemClientSide Besides the methods described above there are also various events that could be used for manipulating the different items and buttons in the RadRibbonBar control. Currently the RadRibbonBar supports the following events:
678
Auto ( ImageRenderingMode.Auto) - When no mode is explicitly selected (or Auto is), RadRibbonBar tries to determine the appropriate rendering mode on per-item basis. We strongly recommend to always explicitly set on of the other two modes Clip and Dual. Simply because there are items with very hard to determine mode scenarios. Perhaps the best example of such item is RibbonBarSplitButton it has a selected button, but at the same time it has the possibility of setting all images directly on it. This makes the determining of the Rendering Mode far too complex and many scenarios cannot be covered automatically. Otherwise the algorithm is basically working as following: if there is a large image set (ImageUrlLarge or DisabledImageUrlLarge), the mode is Dual. If there are no
679
Clip (ImageRenderingMode.Clip) - In this mode the images are assigned through the ImageUrl and DisabledImageUrl. ImageUrl image contains both small and large image for the enabled state of the item, and the DisabledImageUrl contains the images for the disabled state. Images set in the ImageUrlLarge and DisabledImageUrlLarge are disregarded. Dual (ImageRenderingMode.Dual) - When Dual is explicitly set (or resolved to, from Auto), small images are set through ImageUrl and DisabledImageUrl and large images are set through ImageUrlLarge and DisabledImageUrlLarge.
By default the selected value is Auto. As previously mentioned, the ImageRenderingMode can be set on RadRibbonBar and on any RibbonBarItem. This means that you can set a general rule on RibbonBar level and make exceptions on the level of item. In order to fully show the power of this approach, you can find an example here: You can find the complete source for this project at: \VS Projects\RibbonBar\ImageRendering
32.7 Summary
In this chapter you explored the structure of the RadRibbonBar and saw some of the powerful features it provides. You learned how to create a RadRibbonBar. Moreover, youve learned some of the server-side and client-side properties and events of the control. You also learned how to manipulate different items of the RadRibbonBar using both server-side and client-side code. Finally, youve learned how to use Templates in RadRibbonBar. Youve built a simple application that used templates and learned how to find controls in a RadRibbonBar ItemTemplate with a nested control.
680
33.1 Objectives
Explore the features of the RadTreeList control. Explore the RadTreeList design time interface, including Smart Tag and Properties View. Create simple application for binding data using the RadTreeList and presents the most common features.
33.2 Introduction
Telerik RadTreeList is a hybrid control combining treeview and grid in one. It gives you the opportunity for hierarchical representation of the underlying data like in a treeview. In addition it can have multiple columns and provides you with the ability to perform advanced operations like paging, selecting items, etc. The key features of the RadTreelist control are:
Various column types Codeless data-binding using the DataSourceControls in ASP.NET 2.0/3.5 Data-Binding to various data sources which implement the IEnumerable, IList or ICustomTypeDescriptor interfaces Integrated paging Integrated sorting Easily customizable skinning mechanism (setting single Skin property of the treelist) The ShowOuterBorders, ShowTreeLines and GridLines properties allow you to quickly change the appearance Interoperability with RadAjax and loading indicators - dramatically improves the responsiveness of the component, simulates Windows-application like behavior, and minimizes the traffic to the server Single and Multi-Row Server-Side and Client-Side Selection The selected and the expanded state of the items is persisted while navigating through pages.
33.3 Getting-Started
Here we will describe the main features of the RadTreeList and the properties/methods you should know to enable them.
Paging
RadTreeList supports paging functionality which allows the users to view the data, separated in chunks.To enable this functionality in RadTreeList, you should set the AllowPaging property to true. The following methods and properties are exposed in the RadTreeList's server-side Pager API: PageSize Determines the maximum items displayed on a single page PagerStyle-FirstPageToolTipThe text that is displayed when hovering the FirstPage button PagerStyle-NextPageToolTipThe text that is displayed when hovering the NextPage button PagerStyle-PrevPageToolTipThe text that is displayed when hovering the PrevPage button PagerStyle-LastPageToolTip The text that is displayed when hovering the LastPage button PageButtonCount The number of numeric buttons in the pager
681
Sorting
RadTreeList offers sorting capabilities that allows the users to conveniently order the items in the desired direction. To enable this functionality you just have to set AllowSorting property to true and the control will handle the sorting operations automatically. There are three sort modes: - Ascending - orders the items in ascending order - Descending - orders the items in descending order - None - the items are ordered in the way they came from the datasource ("Natural" sort) RadTreeList also supports sorting by multiple datafields - this is the so-called Multi-column sorting. To enable this mode, set the AllowMultiColumnSorting to true. Due to the self-referencing nature of the control, the sorting takes effect "per-level". Basically, this means that each level of the hierarchical structureis sorted independently.
Sorting API: RadTreeList exposes the following properties and methods: AllowMultiColumnSortingDetermines whether the multi-column sorting functionality is enabled. Enables or disables the "natural" sort mode where the items are ordered in the way
682
Selecting
Telerik RadTreeList has built-in mechanism for items selection. You can select items either on the client or on the server as per your requirements. 1.Client-Side Selection: To enable the RadTreeList client-side selection you need to set the ClientSettings.Selecting.AllowItemSelection to true. This will allow you to select an item on mouse click. As a result the OnItemClick, OnItemSelecting and OnItemSelected client-side events of the RadTreeList will be fired so you can perform further actions and handle the item selection in a custom manner. You can also use the below settings to enable additional modes of the client-side selection:
ClientSettings.Selecting.AllowToggleSelection - When set to true (the default value is false) enables you to deselect an item by clicking onone that is alreadyselected. ClientSettings.Selecting.UseSelectColumnOnly - When set to true (the default value is false) prevents users from selecting items on mouse click and forces them to use the TreeListSelectColumn for that purpose.
With RadTreeList you might want to provide the ability for multi-item selection. This is done by setting its AllowMultiItemSelection property to true (its default value is false). And to select a few items at a time, one can use the [Ctrl] and [Shift] keys as in Windows Explorer. Or, in case the AllowToggleSelection property is true, just click on the desired items to select them. Note that when client-side selection is enabled through the AllowItemSelection property, the TreeListSelectColumn selects the items on the client. If the AllowItemSelection property is false, server-side selection is performed. 2.Server-Side Selection: There might be scenarios where you need to perform server-side selection for the RadTreeList items. For that purpose, you can use one of the below approaches:
Add a TreeListSelectColumn and provide the ability to the user to select the desired items through it Use server-side code to programmaticallyselect the treelist items
In both cases, to enable multi-item selection, you need to set the RadTreeList AllowMultiItemSelection property to true. 2.1.Using the TreeListSelectColumn: RadTreeList server-side selection is enabled for the users once you add the TreeListSelectColumn to the RadTreeList Columns collection. You do not need to set any additional properties. Then checking the checkbox rendered in the column marks the corresponding item as selected. As a result, postback is performed and the ItemCommand event is fired with command nameRadTreeList.SelectCommandName. To deselect an item, one should uncheck thecheckbox in theselect column. Then again postback is performed and the ItemCommand event is firedwith command name RadTreeList.DeselectCommandName. ASPX <telerik:RadTreeList ID="RadTreeList1" runat="server" DataKeyNames="EmployeeID" DataSourceID="SqlDataSource1" ParentDataKeyNames="ReportsTo" AllowMultiItemSelection="True" OnItemCommand="RadTreeList1_ItemCommand"> <Columns>
683
684
685
686
Open Editor
Open Editor link displays RadTreeList wizard with Functionality and Appearance sections which lets you customize/configure the RadTreeList control.
687
Functionality The Functionality section allows you to Enable paging and specify thePagerMode and PageSize properties of the treelist. Also you have the ability tochoose the server-side selection type.
688
Appearance In this section you can set the appearance options for the RadTreeList.
689
Choose Columns
The Choose Columns option allows you to set the way columns are generated and visualized.
690
RadTreeListColumn Collection Editorwill let you display only specific data fields from a given database. Moreover, you can define custom properties for the columns that present these fields. You can use the Add button to create differentcolumns in the treelist. The columns will appear in the "Selected Columns" list. You can use the Up and Down buttons to re-order the columns and the Remove button to remove a column from this list.From the "Members" list choose the columns, which you want to bind (display).
691
Ajax Resources
Add RadAjaxManager... - adds a RadAjaxManager component to your Web page, and displays theRadAjaxManager Property Builder where you can configure it. Replace ScriptManager with RadScriptManager - replaces the default ScriptManager component that is added for AJAX-enabled Web sites with RadScriptManager. Add RadStyleSheetManager - adds a RadStyleSheetManager to your Web page.
Learning Center
Links navigate you directly to RadTreeList examples, help, or code library. You can also search the Telerik web site for a given string.
InPlace - you need to set the EditMode property of your RadTreeList control to InPlace. EditForms - you need to set the EditMode property to EditForms. PopUp -you need to set the EditMode property to PopUp.
The default EditMode of the treelist is EditForms. To specify which edit mode will your control, you can set its EditMode property to one of the above values. The edit form types of the RadTreeList are:
692
The default EditFormType of the treelist is AutoGenerated. To specify which edit form type will your control, you can set its EditFormSettings-EditFormType property to one of the above values. When the EditFormType is set to AutoGenerated (the default value), RadTreeList will generate the edit form for you.
Custom editors
RadTreeList provides a straightforward way to specify a non-default editor for an editable column. The RadTreeList.CreateColumnEditor event fires whenever a column editor needs to be initialized. The event argument object of type TreeListCreateColumnEditorEventArgs provides the following properties:
Column - the TreeListEditableColumn instance for which a column editor will be initialized. DefaultEditor - the default ITreeListColumnEditor instance that the column provides. CustomEditorInitializer - a delegate that does not accept parameters and returns an instance of type ITreeListColumnEditor.
You should provide a delegate function to e.CustomEditorInitializer that instantiates and returns an ITreeListColumnEditor object. A column editor instance usually accepts the target editable column in its constructor. With the attached sample code, we provide a custom column editor for the ""Notes" column in the RadTreeList: You can find the complete source for this project at: \VS Projects\TreeList\RadTreeListCustomEditors
693
The difference from the other RadControls is that the radTreeList provides a DetailTemplatewhich gives you the freedom to create and design one extra row for each treelist item. This additional detail row allows databinding the controls within itto the data fields of its parent. Thus, based on your custom preferences you can model the look and feel of the detail item in a non-table-dependant format while at the same time filling it with content related to the parent row. The following sample illustrates one possible usage of the detail itemfeature and the other appearance optionsof RadTreeList: 1. Create new project in Visual Studio and add a RadScriptManager on top of the form. You can also add RadSkinManager and set its Skin property, and a RadFormDecorator control for page styling. 2. Then add the RadTreeList control itself using the below code for it: ASPX <telerik:RadTreeList runat="server" ID="RadTreeList1" DataSourceID="SqlDataSource1" AutoGenerateColumns="false" AllowPaging="true" PageSize="5" DataKeyNames="EmployeeID" ParentDataKeyNames="ReportsTo"> <Columns> <telerik:TreeListBoundColumn DataField="EmployeeID" HeaderText="EmployeeID" UniqueName="EmployeeID"> </telerik:TreeListBoundColumn> <telerik:TreeListBoundColumn DataField="LastName" HeaderText="Last Name" UniqueName="LastName"> </telerik:TreeListBoundColumn> <telerik:TreeListBoundColumn DataField="FirstName" HeaderText="First Name" UniqueName="FirstName"> </telerik:TreeListBoundColumn> <telerik:TreeListBoundColumn DataField="Title" HeaderText="Title" UniqueName="Title"> </telerik:TreeListBoundColumn> <telerik:TreeListBoundColumn DataField="ReportsTo" HeaderText="ReportsTo" UniqueName="ReportsTo"> </telerik:TreeListBoundColumn> </Columns> </telerik:RadTreeList> <asp:SqlDataSource ID="SqlDataSource1" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" ProviderName="System.Data.SqlClient" SelectCommand="SELECT EmployeeID, LastName, FirstName, Title, ReportsTo, Notes FROM Employees" runat="server"></asp:SqlDataSource> 3. Wrap the RadTreeList into RadAjaxPanel omit the page flickering when RadTreeList items are changing their modes 4. Set the ShowOuterBorders,ShowTreeLines and GridLines properties: ASPX <telerik:RadTreeList runat="server" ID="RadTreeList1" DataSourceID="SqlDataSource1" AutoGenerateColumns="false" AllowPaging="true" ShowOuterBorders="true" ShowTreeLines="false" GridLines="None" PageSize="5" DataKeyNames="EmployeeID" ParentDataKeyNames="ReportsTo"> <Columns>
694
695
33.7 Summary
In this chapter we looked at the RadTreeList control and explored its most commonly used features like paging, sorting anditems selection. Learned how to use RadTreeList in Design Time, build its layoutwith ease. You saw how toimplement a sample project on how to manipulate the RadTreeList appearance and create a DetailTemplate.
33.8 Scrolling
Often, when constructing a Web page that contains a treelist, there are design limitations regarding the size of the treelist. In such cases, you may need to enable client-side treelist scrolling so that the treelist can fit it in the allowed space. You can enable scrolling by setting the ClientSettings.Scrolling.AllowScroll property to True (By default its value is False.)
696
When UseStaticHeaders is False, the header scrolls along with the data rows:
If static headers are enabled, the scrollable container includes only the data and footer items. The header and pager are "static" (not scrolled). If static headers are not enabled, the scrollable container includes everything.
697
option to display a special icon (drop clue) that can be changed (manually) depending on the hovered container
set ClientSettings-AllowItemsDragDrop property to true enable client selection by setting the ClientSettings-Selecting-AllowItemSelection property to true
Item Reordering
RadTreeList supports automatic item reordering when SqlDataSource is used. In this case, the developer needs to configure the datasource control to have valid update command (as for automatic operations). When binding to another type of datasource, the reordering should be handled manually via the client/server API.
Server-Side API
OnItemDrop - this event occurs when a RadListView item is dragged and dropped over HTML element (if not cancelled via the client-side API) AllowItemsDragDrop - property which is used to enabledragged and dropped over HTML element (if not cancelled via the client-side API)
Client-Side API
Below you can find a list of all client-side events that can be used when implementing drag and drop operations. It is important to mention, that OnItemDragging and OnItemDropping events can be cancelled by setting the set_cancel property available in their event arguments. A convenient feature of the client-side API is that the control automatically detect some of the invalid reordering operations such as trying to drag a parent item onto its child or trying to drop an item over itself. In these cases, the get_canDrop property will return false when invoked in the OnItemDragging event.
OnItemDragStarted - event is fired when a drag action is started. OnItemDragging- event is fired when a TreeListDataItem is being dragged. OnItemDropping - event is fired when a TreeListDataItem is being dropped. OnItemDropped - event is fired when a TreeListDataItem has been dropped.
33.10Load On Demand
698
699
34.1 Objectives
Build a web user control that contains a RadComboBox with a RadTreeView inside.Reuse this controlin several locations. Use RadControls within a standard FormView control. Use Eval() and Bind() expressions. Build a single grid containing master and detail data with full CRUD functionality. Build two related grids, one containing master data and the other containing detail data, both with CRUD functionality. Make use of template columns containing check boxes.
34.2 Introduction
The material in this chapter may be somewhat heavy going as you will be building user controls that represent "pages" that display in response to the clicking on the tab strip. Each "page" handles full CRUD functionality for Categories, Questions and Exam tables. You will be creating a control that displays allcategories in a RadTreeView that displays within a RadComboBox or on its own. This control will be reused in all three "pages".
We will use the new "CategoriesTree" control together with a standard ASP.NET FormView to add, edit and delete categories. The screenshot below shows RadTextBox controls within the FormView. Each of the FormView templates contains RadTextBox controls bound within the markup using Bind() and Eval() binding expressions.
700
We will be using the grid heavily to access its powerful editing and viewing capabilities. For example, the screenshot below shows exams in one grid and questions in another grid. The questions are filtered by the CategoriesTree user control we will build beforehand. The check boxes in the "Include" column will be checked if a "ExamQuestions" join table record exists for the exam and question combination. You will be using much of the built-in "automatic" ability, but also using template columns to get very specific behaviors from your RadGrid. In fact the"Include" checkboxes are standard checkboxes accessed within code to deliver custom functionality.
701
You can find the complete source for this project at: \VS Projects\ActiveSkill Database Maintenance\Categories Tree
Set the Text property to "Select a Category", DropDownWidth to "300px" and AllowCustomText to true. Open up the CollapseAnimation and ExpandAnimation properties. Set the Type sub-property to be "None". Using the RadComboBox Item Builder dialog (from the Smart Tag Build RadComboBox... option), add a single item. Set the Text and Value item properties blank.
Set the ID property to "StandAloneTreeView". Set the DataFieldID property to "ID", DataFieldParentID to "ParentID", DataTextField to "Title" andValueField to "ID". Using the events ( ) button of the Properties window, locate the NodeClick event. Type in "CategoriesNodeClick" and hit Enter. This will create a server-side event handler that we will code later. Using the events ( ) button of the Properties window, locate the NodeDataBound event. Type in "CategoriesNodeDataBound" and hit Enter. This will create a server-side event handler that we will code later.
4. Select the RadTreeView, right-click and select Copy from the context menu.
702
703
704
705
706
707
708
709
Set the ID property to dsAllCategories. Set the ConnectionString property to "ActiveSkillConnectionString" from the drop down list. Click the ellipses on the SelectQuery property. This brings up the Command and Parameter Editor dialog. Enter the select command: [T-SQL] Select All Categories select ID, ParentID, Title, Description from Category Click the OK button to close the dialog.
2. Below the data source, drop a CategoriesTree control from the Solution Explorer. Set the DisplayMode to "TreeViewOnly". 3. In the "Categories.aspx" code behind add the code below to the FirstLoad() method implementation. [VB] Coding the FirstLoad() Method Public Sub FirstLoad(ByVal args As Dictionary(Of String, String)) CategoriesTree1.InitialLoad(dsAllCtegories) End Sub [C#] Coding the FirstLoad() Method public void FirstLoad(Dictionary<string, string> args) {
710
5. Stop the application. The print for the treeview entries is a little dim so let's make it slightly brighter. In the Solution Explorer, navigate to the \skins\ActiveSkill\TreeView.ActiveSkill.css file and open it. At the top of the file is a CSS selector for ".RadTreeView_ActiveSkill .rtEdit .rtIn input". Change the color for that style from "color:#9F9F9F;" to "color:#CFCFCF;". This will brighten the text very slightly:
6. Set the CategoriesTree DisplayMode property to "DropDown" and re-run the application. Try selecting different items and also click off to the side of the treeview but still within the combo drop down area.
711
7. The downward pointing arrow for the combo box drop down is a little hard to see so we will replace the graphic to make it a little brighter. The image file that controls the appearance for this button is called rcbArrowCell.gif and looks like the image below when you open it in a graphics editing application (e.g. PhotoShop). This kind of image is generically called a "CSS Sprite" where the image represents all of the states that a screen element can be. Using CSSsprites enhances performance by allowing all the images for a screen element to be downloaded at one time. The CSS styles determine which chunk of the image will be displayed. You can edit these files using PhotoShop or any other image editing utility.
Copy the image "rcbArrowCell.gif" from the folder "\VS Projects\Images\ActiveSkill\Admin Database" to "\Skins\ActiveSkill\ComboBox" in your ActiveSkillUI project. This will replace the file that already exists there. Now the combo arrow will look something like this:
712
8. While you're testing out the drop-down functionality of this control, now is a good time to look at some of the decisions made in configuring and coding this control, particularly regarding how the combo box and tree view working together. Starting with the client-side code:
In the ClientNodeClicked event we have a call to stopPropagation() for the combo box's DOM element. This code stops the event from bubbling out from the treeview to the combo box and causing unintended behaviors. In the ClientNodeClicking we call the combo's attachDropDown() method. Without this call, clicking on the treeview will trigger a postback instead of a callback. The click event for the div surrounding the treeview makes a call to StopPropagation(). This ensures that clicking just outside the treeview (but still inside the combo box) is ignored. You get some odd behavior if you don't make this call where the concatenatedcontents of the tree view appear to be displayed in the combo text:
713
You can find the complete source for this project at: \VS Projects\ActiveSkill Database Maintenance\Categories
Prepare Layout
RoadMap
Before we get going, here's a general road map that shows how the markup for Categories.aspx will be structured. The screenshot below shows the major parts of the markup commented and with the elements collapsed so that you can see all portions of the page at one time.
Data Sources: You have already defined the "dsAllCategories" data source when testing the CategoriesTree user control. You will add a second data source "dsCategory" to handle the add/update/delete jobs for a single category record. Toolbar with add, edit and delete buttons: The tool bar buttons have values corresponding to constants on the server for CRUD operations. The images for the button are actually retrieved from the Grid skin images. Treeview with Categories: This is the CategoriesTree control you added and tested on this page. Fieldset containing FormView: The standard ASP.NETFormView control has Item, Edit and Insert templates that canholdRadTextBoxes and allow binding to database values on the server using binding expressions. The FormView is the area where the admin actually enters a category name, category description and clicks the "Update" or "Cancel" buttons. The FormView also has an OnItemCreated event that gives us a chance to retrieve a newly generated category ID to plug back into our treeview.
714
On the Select tab, select the "Stored Procedure" radio button. From the drop down list select "Skill_Category_SelectWhere".
715
On the Update tab, select the "Stored Procedure" radio button. From the drop down list select "Skill_Category_Update". On theInsert tab, select the "Stored Procedure" radio button. From the drop down list select "Skill_Category_Insert". On theDelete tab, select the "Stored Procedure" radio button. From the drop down list select "Skill_Category_Delete". Click the Next button.
6. Click the Next button. 7. Click the Finish button to close the dialog. 8. In the Properties window for the SqlDataSource, click the DeleteQuery property ellipses. This will again display the Command and Parameter editor for the delete query. 9. In the "Parameter source:" drop down list, select "Control".
Set the ControlID property to "CategoriesTree1". Set the Name property to "ID". Set the PropertyName to "CategoryID" Set the Type to "Int32".
716
10. Click the OK button to close the dialog. 11. In the Properties window for the SqlDataSource, click the InsertQuery property ellipses. In this case you will have to set properties for more than one parameter and these parameters will be populated from code. Configure each parameter as follows:
ID: Leave the "Parameter Source" as "None", Direction to "InputOutput", Name to "ID", Type to "Int32". ParentID: Leave the "Parameter Source" as "None", Direction to "Input", Name to "ParentID", Type to "Int32". Title: Leave the "Parameter Source" as "None", Direction to "Input", Name to "Title", Type to "String". Description: Leave the "Parameter Source" as "None", Direction to "Input", Name to "Description", Type to "String".
717
12. Click the OK button to close the dialog. 13. In the Properties window for the SqlDataSource, click the UpdateQuery property ellipses. Configure the parameters as follows:
ID: Set the "Parameter Source" as "Control", ControlID as "CategoriesTree1", Property Name as "CategoryID", Direction to "Input", Name to "ID", Type to "Int32". ParentID:Set the "Parameter Source" as "Control", ControlID as "CategoriesTree1", Property Name as "ParentCategoryID", Direction to "Input", Name to "ParentID", Type to "Int32". Title: Leave the "Parameter Source" as "None", Direction to "Input", Name to "Title", Type to "String". Description: Leave the "Parameter Source" as "None", Direction to "Input", Name to "Description", Type to "String".
718
14. Click the OK button to close the dialog. At this point the markup for "dsCategory" is: [ASP.NET] The Markup for dsCategory <asp:SqlDataSource ID="dsCategory" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" DeleteCommand="Skill_Category_Delete" InsertCommand="Skill_Category_Insert" UpdateCommand="Skill_Category_Update" DeleteCommandType="StoredProcedure" InsertCommandType="StoredProcedure" UpdateCommandType="StoredProcedure" CancelSelectOnNullParameter="False" OnInserted="dsCategory_Inserted" SelectCommand="Skill_Category_SelectWhere" SelectCommandType="StoredProcedure"> <SelectParameters> <asp:Parameter Name="ID" Type="Int32" /> </SelectParameters> <DeleteParameters> <asp:ControlParameter ControlID="CategoriesTree1" Name="ID" PropertyName="CategoryID" Type="Int32" /> </DeleteParameters> <UpdateParameters> <asp:ControlParameter ControlID="CategoriesTree1" Name="ID" PropertyName="CategoryID" Type="Int32" /> <asp:ControlParameter ControlID="CategoriesTree1" Name="ParentID" PropertyName="ParentCategoryID" Type="Int32" /> <asp:Parameter Name="Title" Type="String" />
719
Set the Text property to "Add Category", ImageUrl to "../Skins/ActiveSkill/Grid/AddRecord.gif"and Enabled tofalse. Set the Text property to "EditCategory", ImageUrl to "../Skins/ActiveSkill/Grid/Update.gif"and Enabled tofalse. Set the Text property to "Delete Category", ImageUrl to "../Skins/ActiveSkill/Grid/Delete.gif"and Enabled tofalse.
2. You will need to finish the definition of the tool bar within the markup because it requiresapplying a style and a few binding expressions. First add Style="float: none" to the RadToolBar element. Then add binding expressions tothe Value properties of all three buttons:
Value='<%#INSERT_CATEGORY%>' Value='<%#EDIT_CATEGORY%>' Value='<%#DELETE_CATEGORY%>' The finished tag should look like the markup below. Note that we will need to call Page.DataBind() for the binding expressions to be evaluated: [ASP.NET] Defining the RadToolBar <%--toolbar with add, edit, delete buttons--%> <telerik:RadToolBar ID="tbarCategories" runat="server" OnButtonClick="tbarCategories_ButtonClick" Style="float: none" > <items> <telerik:RadToolBarButton runat="server" Text="Add Category" Value='<%#INSERT_CATEGORY%>' ImageUrl="../Skins/ActiveSkill/Grid/AddRecord.gif" Enabled="False"> </telerik:RadToolBarButton> <telerik:RadToolBarButton runat="server" Text="Edit Category"
720
The CategoriesTree
After the RadToolBar should come the CategoriesTree control you added when testing the control. Verify that the DisplayMode is set to TreeViewOnly. Surround the CategoriesTree control with a div. The div ID should be "CategoriesTreeDiv" and have a style of "float: left". The style keeps the FormView (which comes next) from being bumped off onto the next line. [ASP.NET] The CategoriesTree <%--treeview with categories--%> <div id="CategoriesTreeDiv" style="float: left;"> <uc1:CategoriesTree ID="CategoriesTree1" runat="server" DisplayMode="TreeViewOnly" /> </div>
Set their ImageUrl properties to "../Images/cancel_btn_2.png" and "../Images/update_btn_2.png" respectively. Double-click both the cancel and update buttons to create OnClick event handlers for each. Copy the two text boxes and the div holding the two buttons onto the clipboard.
9. Using the FormView Smart Tag, navigate to the InsertItemTemplate and paste the contents of the clipboard, i.e. the two text boxes, the div and the two buttons. 10. Navigate back to the ItemTemplate and set the two RadTextBox ReadOnly properties to true and the Enabled properties to false. 11. Go to the source for the page to work with the FormView markup and add binding expressions.
721
In the ItemTemplate, set the Text properties for the two RadTextBox controls to'<%# Eval("Title") % >' and '<%# Eval("Description") %>' respectively. This will display the Category table Title and Description columns when the FormView is in ReadOnly mode. In the EditItemTemplateset the Text properties for the two RadTextBox controls to'<%# Bind("Title") %>' and '<%# Bind("Description") %>' respectively. This will allow editing of the Category table Title and Description columns when the FormView is in Edit mode. Repeat the step above and add binding expressions for the InsertItemTemplate. The completed markup should look like the example below: [ASP.NET] Defining the FormView
722
723
724
725
Page_Load: The NodeClick handler for the CategoriesTree needs to be re-added on every postback. Cancel and Update Click Events: These events occur in response to the admin clicking on cancel or update buttons within the FormView. Canceling works the same for both Insert and Edits The FormView mode is changed back to ReadOnly and the toolbar button state is refreshed to reflect this.The save of an insert causes a new node to be created using the Title andDescription entry from the FormView.The record is inserted and the FormView is returned to a read-only state. Saving an edit is quite similar to insert except the corresponding updatemethods of the CategoriesTree and DataSource are called instead. Inserted Event Handler: When the category is inserted to the database we need to find out what the new generated ID is and get that back to the tree node Value property. You can retrieve the generated value of an InputOutput parameter using the SqlDataSource OnInserted event. OnInserted has aSqlDataSourceStatusEventArgs argument that lets you access the parameters of the stored procedure responsible for inserting the category. ToolBar Button Click Event Handler: When a button on the toolbar is clicked, this event handler retrieves the Value property that contains the operation to perform. The Value property is populated by a binding expression that uses the same threeconstants used in this event handler. If Insert or Edit buttons were clicked, the FormView mode is changed so that the admin can enter values. If the Delete button is clicked, the delete happens immediately. FormView OnItemCreated Event Handler: As items in the FormView are created, this event handler attaches attributes so that the image buttons can respond to onmouseover and onmouseout client events. When the user hovers over a button, the button responds visually.
726
727
728
729
730
this.DataBind() to bind the page. This will allow the binding expression in the RadToolBar to occur. Perform the Initial bind of the FormView. Update the button state to agree with the editing mode.
Update your FirstLoad() implementation with the code below: [VB] Implementing FirstLoad() #region IASControl Members Public Sub FirstLoad(ByVal args As System.Collections.Generic.Dictionary(Of String, String)) ' bind the page to emit binding expressions into the markup ' bind here instead of page_load because categoriestreeview is counting on ' the values already being populated by the call to InitialLoad() Me.DataBind() CategoriesTree1.InitialLoad(dsAllCategories) fvCategories.DataBind() UpdateButtonState() End Sub #End Region [C#] Implementing FirstLoad() #region IASControl Members public void FirstLoad(System.Collections.Generic.Dictionary<string, string> args) { // bind the page to emit binding expressions into the markup // bind here instead of page_load because categoriestreeview is counting on // the values already being populated by the call to InitialLoad() this.DataBind(); CategoriesTree1.InitialLoad(dsAllCategories); fvCategories.DataBind(); UpdateButtonState(); } #endregion
731
You can find the complete source for this project at: \VS Projects\ActiveSkill Database Maintenance\Questions
Prepare Layout
Roadmap
The overall layout of the markup for this user control looks something like the condensed view shown in the screenshot below. The user control has three data sources: the "all categories" data source that supplies the CategoriesTree, dsCategoryQuestions that feeds the MasterTableView of the grid and dsResponse that feeds the detail table of the grid.
732
dsAllCategories: supplies all categories to the CategoriesTree control. dsCategoryQuestions: supplies questions for the category selected in the CategoriesTree to a RadGrid. The questions are displayed in the MasterTableView. The data source provides add, update and delete functionality for the grid. The category ID is supplied by the CategoryTree and the other parameters are assigned programmatically. dsResponse: This data source returns a list of responses for a given question and can add, update and delete responses.
[ASP.NET] Adding the DataSource Controls <%--Data Sources--%> <asp:SqlDataSource ID="dsAllCategories" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="SELECT [ID], [ParentID], [Title], [Description] FROM [Category]"> </asp:SqlDataSource> <asp:SqlDataSource ID="dsCategoryQuestions" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="Skill_QuestionsByCategory_Select" SelectCommandType="StoredProcedure" DeleteCommand="Skill_Question_Delete" DeleteCommandType="StoredProcedure" InsertCommand="Skill_Question_Insert" InsertCommandType="StoredProcedure" UpdateCommand="Skill_Question_Update" UpdateCommandType="StoredProcedure"> <SelectParameters> <asp:Parameter Name="CategoryID" Type="Int32" /> </SelectParameters> <DeleteParameters> <asp:ControlParameter ControlID="CategoriesTree1" Name="ID" PropertyName="CategoryID" Type="Int32" /> </DeleteParameters> <UpdateParameters> <asp:Parameter Name="HTML" Type="String" /> <asp:Parameter Name="Enabled" Type="Boolean" /> <asp:ControlParameter ControlID="CategoriesTree1" Name="CategoryID" PropertyName="CategoryID" Type="Int32" /> <asp:Parameter Name="ID" Type="Int32" /> </UpdateParameters> <InsertParameters> <asp:Parameter Direction="InputOutput" Name="ID" Type="Int32" /> <asp:ControlParameter ControlID="CategoriesTree1" Name="CategoryID" PropertyName="CategoryID" Type="Int32" /> <asp:Parameter Name="HTML" Type="String" /> <asp:Parameter Name="Enabled" Type="Boolean" /> </InsertParameters> </asp:SqlDataSource> <asp:SqlDataSource ID="dsResponse" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" DeleteCommand="Skill_Response_Delete" DeleteCommandType="StoredProcedure" InsertCommand="Skill_Response_Insert" InsertCommandType="StoredProcedure"
733
ID: "gridQuestions". AllowAutomaticDeletes: true. AutoGenerateColumns: false. GridLines: None. Skin: leave thisblank.
2. Open up the MasterTableView property and set the following sub properties:
CommandItemDisplay: Top DataKeyNames: "ID" EditMode: InPlace Name: "Question" (note: this will be used to identify the tableview in some of the command events) NoMasterRecordsText: "No questions to display for this category"
3. Also in MasterTableView, open up the DetailTables sub-property, add a detail table and set the following properties to the new detail table:
734
4. In the markup, add the columns below to the MasterTableView <Columns>. The markup can be added just inside the closing </MasterTableView> tag. You can also build the column list from the Property Builder or Columns collection editor. At the time of this writing, the GridHTMLEditorColumn type was not available from these two options, so it will be more straightforward to define all columns at once here. The GridHTMLEditorColumn is designed with a limited number of tools due to performance reasons so that instances rendered for each edited row are loaded faster. In most cases you don't need the entire set of RadEditor tools when using it as column editor in RadGrid. If you do require a larger toolset, embed a RadEditor using a template column. See this article for more onusing a RadEditor in a template column (http://www.telerik.com/support/kb/article/b454K-tae-b454T-cbb-b454ccbb.aspx). There are a few things to notice about the columns defined below. The Visible property for key column"ID"is false. The "HTML" column uses a GridHTMLEditorColumn type. The columns that have images have imageURLs that point to \Skins\ActiveSkill\Grid directory. [ASP.NET] Adding Columns <Columns> <telerik:GridBoundColumn DataField="ID" DataType="System.Int32" HeaderText="ID" SortExpression="ID" UniqueName="ID" Visible="False"> </telerik:GridBoundColumn>
735
736
DetailTableDataBind ItemCreated NeedDataSource In the later sections we will implement these event handlers.
737
738
Each event handler has it's own unique Item object. Looking at the insert and update commands, they use GridDataInsertItem and GridEditableItem respectively. The item's ExtractValues() method is used to fill a HashTable with key/value pairs. You can see how the HashTable is used to extract column datausing the column name to indexthe HashTable. To know which table is to be updated or inserted to you can get the OwnerTableView.Name from the e.Item parameter passed in. When you prepared the layout for this grid, the Name for the MasterTableView and the detail table view was assigned at that time. When inserting to the detail table you need to know the foreign key to the master table "QuestionID". You can get that key value by traversing up from the OwnerTableView to the ParentItem and then extracting from the DataKeyValue property. See the InsertCommand handler in the 'Case "Response" for example of this technique. The UpdateCommand handler does not need to do this because "QuestionID" is already populated in the row for the response. The DeleteCommand only needs the key value for the record being deleted. Here you can first extract the OwnerTableView DataKeyValues array.Index into the array using the current row (e.Item.ItemIndex) and the key column using the column name ("ID").
[VB] Handling the Grid CRUD Commands #region grid crud commands Protected Sub gridQuestions_InsertCommand(ByVal source As Object, ByVal e As GridCommandEventArgs) ' Get the item that appears when grid is in Insert Mode. ' Use the item object ExtractValues()method ' to fill a HashTable with values for the current row. Dim insertItem As GridDataInsertItem = DirectCast((e.Item.OwnerTableView.GetInsertItem()), GridDataInsertItem) Dim ht As New Hashtable() insertItem.ExtractValues(ht) ' Navigate to the OwnerTableView for the Name property. ' In this case the Name will be "Question", the master table view, ' or "Response", the detail table view. ' Load up the appropriate data source parameters from the hash table ' and call Insert() method. Select Case e.Item.OwnerTableView.Name Case "Question" dsCategoryQuestions.InsertParameters("HTML").DefaultValue = ht("HTML").ToString() dsCategoryQuestions.InsertParameters("Enabled").DefaultValue = ht("Enabled").ToString() dsCategoryQuestions.Insert()
739
740
741
742
743
744
The edit mode for Insert and Edit will show in a pop-up dialog as shown in the screen shot below:
You can find the complete source for this project at: \VS Projects\ActiveSkill Database Maintenance\Create Exams
745
dsAllCategories: Supplies all categories to the CategoriesTree control. dsExams: Supplies all available exams. Handles add/update/delete operations. dsExamQuestions: Returns a list of questions for the selected exam and category. Handles add and delete operations.
[ASP.NET] Adding the DataSource Controls <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="CreateExams.ascx.cs" Inherits="Telerik.ActiveSkill.UI.Admin.CreateExams" %> <%@ Register Src="../Controls/CategoriesTree.ascx" TagName="CategoriesTree" TagPrefix="uc1" %> <%@ Register Assembly="Telerik.Web.UI, Version=2008.2.723.35, Culture=neutral, PublicKeyToken=121fae78165ba3d4" Namespace="Telerik.Web.UI" TagPrefix="telerik" %> <%--Data Sources--%> <asp:SqlDataSource ID="dsAllCategories" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="SELECT [ID], [ParentID], [Title], [Description] FROM [Category]"> </asp:SqlDataSource> <asp:SqlDataSource ID="dsExams" runat="server" ConnectionString="<%$ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="SELECT [ID], [Title], [Description], [PassPercent], [ModifyDate] FROM
746
2. Open up the MasterTableView property and set the following sub properties:
747
Name: "Exam" NoMasterRecordsText: "No exams to display" ), add handlers for the following events:
OnInsertCommand OnNeedDataSource OnDeleteCommand OnUpdateCommand OnSelectedIndexChanged OnDataBound In the later sections we will implement these event handlers as well as add the columns.
2. Open up the MasterTableView property and set the following sub properties:
CommandItemDisplay: Top DataKeyNames: "ID" EditMode: InPlace Name: "Question" NoMasterRecordsText: "No questions to display" ), add handlers for the following events:
OnNeedDataSource OnItemDataBound
748
Adding Columns
Add columns to the exam grid: [ASP.NET] Adding Columns to gridExams <Columns> <telerik:GridButtonColumn CommandName="Select" Text="Select" UniqueName="column1" HeaderText="Select" ImageUrl="../Skins/ActiveSkill/Grid/Update.gif" ButtonType="ImageButton"> </telerik:GridButtonColumn> <telerik:GridBoundColumn DataField="Title" HeaderText="Title" UniqueName="Title"> </telerik:GridBoundColumn> <telerik:GridBoundColumn DataField="Description" HeaderText="Description" UniqueName="Description"> </telerik:GridBoundColumn> <telerik:GridBoundColumn DataField="PassPercent" DataType="System.Int32" HeaderText="Pass Percent" UniqueName="PassPercent"> </telerik:GridBoundColumn> <telerik:GridEditCommandColumn ButtonType="ImageButton" CancelImageUrl="../Skins/ActiveSkill/Grid/Cancel.gif" EditImageUrl="../Skins/ActiveSkill/Grid/Edit.gif" InsertImageUrl="../Skins/ActiveSkill/Grid/Update.gif" UpdateImageUrl="../Skins/ActiveSkill/Grid/Update.gif"> </telerik:GridEditCommandColumn> <telerik:GridButtonColumn UniqueName="ExamsDeleteColumn" ButtonType="ImageButton" CommandName="Delete" ImageUrl="../Skins/ActiveSkill/Grid/Delete.gif" Text="Delete"> </telerik:GridButtonColumn> </Columns> Add columns to the exam questions grid: [ASP.NET] Adding Columns to gridExamQuestions <Columns> <telerik:GridBoundColumn UniqueName="ID" DataField="ID" DataType="System.Int32" Display="False" Visible="False" FilterImageUrl="../Skins/ActiveSkill/Grid/Filter.gif" SortAscImageUrl="../Skins/ActiveSkill/Grid/SortAsc.gif" SortDescImageUrl="../Skins/ActiveSkill/Grid/SortDesc.gif"> </telerik:GridBoundColumn> <telerik:GridBoundColumn UniqueName="IsInExam" DataField="IsInExam" DataType="System.boolean" Display="False"> </telerik:GridBoundColumn> <telerik:GridTemplateColumn UniqueName="IsInExamColumn" HeaderText="Include"> <ItemTemplate> <asp:CheckBox ID="cbIsInExam" runat="server" AutoPostBack="true" OnCheckedChanged="IsInExamCheckChanged"></asp:CheckBox> </ItemTemplate> </telerik:GridTemplateColumn> <telerik:GridHTMLEditorColumn DataField="HTML" HeaderText="Question"
749
The EditMode property of the MasterTableView is set to "PopUp". The EditFormSettingstag of the Exam grid has aCaptionDataField property set to "Title". The exam "Title" column did will display in the grid pop-up caption area. Note that you can also use CaptionFormatString along with CaptionDataField,e.g. "The title of the exam is {0}". The NoMasterRecordsText property of the Exam grid MasterTableView lets you set custom text to display when there are no records, rather than the generic default message. The "cbIsInExam" check box is found within a GridTemplateColumn of the questions grid. You will be accessing this check box in code later to implement custom behavior, so take a quick look at it now. The AllowAutomaticDeletes property is enabled for the exam grid. This allows us to leave out the data source Delete() method call. Note that you still have to set up the data source delete parameters and rebind the grid afterward. In the GridEditCommandColumn that displays the edit, insert or cancel buttons has a ButtonType of "ImageButton" and that the imageURLsreuse grid images found in the \skins directory. The field set surrounding the exam questions has a legend element that is bound to the ExamTitle property of the "page".
Add Properties
This page uses the property ExamTitle in a binding expression within the legend. The property isrefreshed whenever a new row is selected in the exam grid. [C#] Defining Properties #region properties Private Const ExamTitleKey As String = "ExamTitleKey" Public Property ExamTitle() As String Get Return IIf(ViewState(ExamTitleKey) = Nothing,"",ViewState(ExamTitleKey).ToString()) End Get Set ViewState(ExamTitleKey) = value End Set End Property #End Region properties [C#] Defining Properties #region properties private const string ExamTitleKey = "ExamTitleKey"; public string ExamTitle { get { return ViewState[ExamTitleKey] == null ? "" : ViewState[ExamTitleKey].ToString();
750
751
Add the code below to the Page_Load event handler. Attach the CategoriesTree NodeClick every time the page loads. Add the code for "IsInExamCheckChanged" to handle the OnCheckChanged event for the "cbIsInExam" checkbox. How do you get the data associated with the checkbox?There is no CheckBox.Tag or Value. Instead, use the naming container that contains the checkbox,which happens to be a GridDataItem. This check box iscontainedin a questions grid template column. To get at data for the row associated with the checkbox, snag the sender parameter and cast it to be CheckBox. Then step up to the checkbox NamingContainer and cast that to be a GridDataItem. You can use the GridDataItem.GetDataKeyValue() to extract the "QuestionID" for the row. If the check box is being checked, a record is added to the ExamQuestions join table, otherwise the record is deleted.
[VB]Handling Page Events #region page events Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) ' add the node click event handler every page load AddHandler CategoriesTree1.NodeClick, AddressOf CategoriesTree1_NodeClick End Sub ' OnCheckChanged event handler Public Sub IsInExamCheckChanged(ByVal sender As Object, ByVal e As EventArgs) ' Toggle the "IsInExam" checkbox and either insert or ' delete the corresponding record Dim cb As CheckBox = (TryCast(sender, CheckBox)) ' How do you get the data associated with the checkbox? ' There is no CheckBox.Tag or Value. ' Use the naming container that holds the checkbox, ' which happens to be a GridDataItem. Dim item As GridDataItem = DirectCast(cb.NamingContainer, GridDataItem) Dim id As String = item.GetDataKeyValue("ID").ToString() If cb.Checked Then dsExamQuestions.InsertParameters("QuestionID").DefaultValue = id dsExamQuestions.Insert() Else dsExamQuestions.DeleteParameters("QuestionID").DefaultValue = id dsExamQuestions.Delete() End If End Sub #End Region [C#]Handling Page Events #region page events protected void Page_Load(object sender, EventArgs e) { // add the node click event handler every page load CategoriesTree1.NodeClick += new RadTreeViewEventHandler(CategoriesTree1_NodeClick); }
752
The CRUD command events are essentially the same structure as used in the Questions maintenance. For InsertCommand and UpdateCommand, the operation-appropriate item object is retrieved, its ExtractValues() method called to fill ahash table and the hash table is used to fill data source parameters before calling Insert() or Update(). DeleteCommand is also the same pattern from Questions maintenance. Here the OwnerTableView DataKeyValues array is used to extract the primary key value, and that value is used to populate data source parameters. Because the AllowAutomaticDeletes property
753
gridExams_NeedDataSource simply assigns the exam grid data source. gridExams_SelectedIndexChanged callsthe private method ExamQuestionsRefresh() to resync the legend and the questions grid with the current selected row of the exam grid. Once the exam grid is bound, gridExams_DataBound selects the first exam row if nothing else has been selected.
[VB] Handling Exam Grid Events #region exams grid events Protected Sub gridExams_InsertCommand(ByVal source As Object, ByVal e As Telerik.Web.UI.GridCommandEventArgs) ' Get the item that appears when grid is in Insert Mode. ' Use the item object ExtractValues()method ' to fill a HashTable with values for the current row. Dim insertItem As GridEditFormInsertItem = DirectCast((e.Item.OwnerTableView.GetInsertItem ()), GridEditFormInsertItem) Dim ht As New Hashtable() insertItem.ExtractValues(ht) ' Load data source parameters from the hash table and insert the record. dsExams.InsertParameters("Title").DefaultValue = ht("Title").ToString() dsExams.InsertParameters("Description").DefaultValue = ht("Description").ToString() dsExams.InsertParameters("PassPercent").DefaultValue = ht("PassPercent").ToString() dsExams.Insert() ' The underlying data has now changed so rebind e.Item.OwnerTableView.Rebind() End Sub Protected Sub gridExams_UpdateCommand(ByVal source As Object, ByVal e As GridCommandEventArgs) ' Get the item that appears when grid is in Update Mode. ' Use the item object ExtractValues()method ' to fill a HashTable with values for the current row. Dim item As GridEditableItem = TryCast(e.Item, GridEditableItem) Dim ht As New Hashtable() item.ExtractValues(ht) ' Load data source parameters from the hash table and update the record. Dim dataKeys As GridDataKeyArray = e.Item.OwnerTableView.DataKeyValues Dim id As String = dataKeys(e.Item.ItemIndex)("ID").ToString() dsExams.UpdateParameters("ID").DefaultValue = id dsExams.UpdateParameters("Title").DefaultValue = ht("Title").ToString() dsExams.UpdateParameters("Description").DefaultValue = ht("Description").ToString() dsExams.UpdateParameters("PassPercent").DefaultValue = ht("PassPercent").ToString() dsExams.Update() ' The underlying data has now changed so rebind e.Item.OwnerTableView.Rebind() End Sub Protected Sub gridExams_DeleteCommand(ByVal source As Object, ByVal e As GridCommandEventArgs) ' Extract the OwnerTableView DataKeyValues array. ' Index into the array using the current row (e.Item.ItemIndex) ' and the key column of the primary key("ID"). Dim dataKeys As GridDataKeyArray = e.Item.OwnerTableView.DataKeyValues Dim id As String = dataKeys(e.Item.ItemIndex)("ID").ToString() ' You don't need to call the data source Delete() here
754
ByVal e As EventArgs)
755
756
757
Altering the graphic elements of the row background. Changing thefont of the selected text within the CSS.
In this case we're going to take theeasier and shorter way out by just changing the font to a brighter color. The general pattern for changing the graphic was touched on when we first built the CategoryTree control in "Databind and Use the Control" where we changed the default drop down arrow. If you want to alter the selected row graphic in PhotoShop or some other graphics utility, look in the \ActiveSkillUI\Skins\Grid folder for the file called "Sprite.gif". 1. Locate Grid.ActiveSkill.CSS in the \skins folder and open it. 2. Find the first instance of ".SelectedRow_ActiveSkill" in the file. 3. Change the color to "color:#FFF". [CSS] Changing the Selected Row Style .SelectedRow_ActiveSkill { background:url('Grid/sprite.gif') 0 -300px repeat-x #343434; /* RadControls Step by Step Tutorial */ color:#FFF; } The new style should make the font for the selected row pop out a little more like the example below.
Add, edit and delete exams. Notice that the record displays in a pop-up due to the EditMode property setting. Filter questions using the CategoriesTree control. Check mark some of the questions to include them in an exam. Switch selection between exams to see the effect on the checkboxes. If you are on "ExamA" and check "Question 1", move to "Exam B" and back to "Exam A", the check mark should persist.
758
759
35.1 Objectives
Build the exam taking functionality. Use JavaScript objects to wrap client code. This will include using MS AJAX Library functionality including registering of namespaces, classes, inheritance and events. Bind RadGrid data on the client. Consume web services on the client. Use LINQ to SQL to retrieve the exam data.
Add the user controls for each "page". Implement the IASControl interface as we did in the Admin page. Define the user home page markup and code behind. This step will be similar to the Admin page,but we will trigger the page change from a client event that triggers an AjaxRequest event. Using the client event/AjaxRequest combinationwill let us change user controls from just about any user interface trigger, including from the RadGrid row click, the RadTabStrip tab click and from standard HTML buttons firing JavaScript. We will wrap the JavaScript required for this mechanism neatly in a JavaScript object. Add the code-behind for the user home page. This again will be quite similar to the Admin home page, but the server TabClick event will be replaced with a AjaxRequest server event. We will also add the ability to pass arguments that travel from the client, through the AjaxRequest event and passed along to the IASControl FirstLoad() method. For example, when the user clicks the row of the grid containing an exam, the exam ID is picked up and passed to the AjaxRequest to the"question" page FirstLoad() where the exam ID is retrieved and used to populate a data structure withthedata for the entire exam.
You can find the complete source for this project at: \VS Projects\ActiveSkill Adding User Functionality\CS\001
760
761
762
Change the RadTabStrip "tsMain" tabs collection to point at our new usercontrols "TakeExamChoose" and "ScheduleExams". The tsMain ClickSelectedTab property should be set to true. Setting ClickSelectedTab to true will allow us to click the tab and have the click events execute even when the clicked tab is already selected. This is the behavior we want if we're in the middle of an exam and want to choose a new exam. Add a OnClientTabSelected event handler and name it "ClientTabSelected". Eliminate the server TabClick event. The markup for tsMain should look like the example below. [ASP.NET] Changing the TabStrip <telerik:RadTabStrip ID="tsMain" runat="server" Orientation="VerticalRight" ClickSelectedTab="true" SelectedIndex="0" OnClientTabSelected="ClientTabSelected"> <Tabs> <telerik:RadTab runat="server" Text="Take Exam" Value="TakeExamChoose.ascx" ImageUrl="~/images/Exams.png"> </telerik:RadTab> <telerik:RadTab runat="server" Text="Schedule" Value="ScheduleExams.ascx" ImageUrl="~/images/Schedule.png"> </telerik:RadTab> </Tabs> </telerik:RadTabStrip>
4. Addthis block of JavaScriptcode just inside the <body> tag. pageLoad() is an event that fires courtesy of having the ScriptManager on the page. This provides an opportunity to create an instance of our DynamicControl object that can be used everywhere in the exam pages. The OnClientTabSelected event handler fires when the user clicks a tab, which in turns causes DynamicControl to load a new user control. [JavaScript] Handling the PageLoad and the OnClientTabSelected Events <telerik:RadScriptBlock ID="RadScriptBlock1" runat="server"> <script type="text/javascript"> /* -- Client event handlers -- */ function pageLoad() { // if there isn't a global instance of DynamicControl, // create it and pass a reference to the RadAjaxManager client // object. if (window.DynamicControl == null) { window.DynamicControl = new ActiveSkill.DynamicControl( $find("<%= RadAjaxManager1.ClientID %>")); } } function ClientTabSelected(sender, args) { // use the DynamicControl load() method to swap user controls. window.DynamicControl.load(args.get_tab().get_value(), ''); } </script> </telerik:RadScriptBlock> 5. Add references to the ScriptManager. This can be done either in the Properties window using the Services and Scripts collections or within the markup. Later, the TakeExamQuestion.ascx control will be consuming a web service and several JavaScript files. The web service path is the same path that can be used directly in a browser to display the methods available for the server and to test that the web service is working.
763
764
765
766
767
You can find the complete source for this project at: VS Projects\ActiveSkill Adding User Functionality\CS\002 1. Add a SqlDataSource to the control. Set the ID property to be "dsExam". Point the ConnectionString property at the ActiveSkillConnectionString we've been using thus far. Set the SelectCommand property to "Skill_Exam_Select" and SelectCommandType to "StoredProcedure". You can configure the data source in the designer or in the markup. The markup should look something like the example below when you're finished. [ASP.NET] Defining the SqlDataSource <%--Data sources --%> <asp:SqlDataSource ID="dsExam" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="Skill_Exam_Select" SelectCommandType="StoredProcedure"> </asp:SqlDataSource> 2. Add a RadGrid to the control. Set the ID property of the grid to "gridExam".Set the other RadGrid properties:
768
A GridBoundColumn with DataField property "ID" and Visible property "false". A GridTemplateColumn with UniqueName "TemplateColumn" and HeaderText "Select an Exam".
EnableRowHoverStyle when true highlights the row that the mouse is currently over. If Selecting.AllowRowSelect is true, you can still select rows on the client side, but there's no visual feedback as the mouse passes over. Finally, you need to respond to the ClientEvents.OnRowSelected event. You can use the args passed to the event to get at the key value for the row (specified by ClientDataKeyNames): mykeyvalue = args.getDataKeyValue("id"); 6. From the Smart Tag select Edit Templates. Using the Smart Tag menu, navigate to the ItemTemplate. 7. Dropa standard ASP.NET Label control on the ItemTemplate. Set the ID property to "lblTitle" and CssClass propertyto "skillTitle".From the label's Smart Tag select Edit Bindings... Provide a custom data binding 'Eval("Title")' to the Text property of the label:
769
8. Use the enter key to add a hard break (<br>) after this label. 9. Drop five more Labels in the template and set the properties as follows:
ID: "lblDescription", CssClass: "skillNormal",Text binding expression: '<%# Eval("Description") %>'. Use the enter key to add a hard break (<br>) after this label. CssClass: "skillNormal",Text: 'Number of questions:'. ID: "lblNumberOfQuestions", CssClass: "skillBlue",Text binding expression: '<%# Eval ("NumberOfQuestions") %>'. Use the enter key to add a hard break (<br>) after this label. CssClass: "skillNormal",Text: "Percentage required to pass: %'. ID: "lblPercent", CssClass: "skillNormal",Text binding expression: '<%# Eval("PassPercent") %>'. Use the enter key to add a hard break (<br>) after this label.
10. Add a RadSlider after the last label. Set the ID property to "sldPassPercent", Enabled to "false", MaximumValue to "100" and MinimumValue to "0". Set properties ShowDecreaseHandle, ShowDraghandle and ShowIncreaseHandle all to "false". Bind the Value propertyto the PassPercent. You can use the Edit Bindings... dialog in the same way you did with the previous Label controls, but in this case, check the "Show all Properties" checkbox, locate Value in the Bindable Properties list, then set the custom binding to '<%# 'Eval("PassPercent") %>'. You can also populate the bindings directly in the markup. The markup for the grid should look like the example below. [ASP.NET] The RadGrid Definition <%--Grid--%> <telerik:RadGrid ID="gridExam" runat="server" AutoGenerateColumns="False" GridLines="None" OnNeedDataSource="gridExam_NeedDataSource" PageSize="3" AllowPaging="True"> <PagerStyle FirstPageImageUrl="../Skins/ActiveSkill/Grid/PagingFirst.gif" LastPageImageUrl="../Skins/ActiveSkill/Grid/PagingLast.gif" NextPageImageUrl="../Skins/ActiveSkill/Grid/PagingNext.gif" PrevPageImageUrl="../Skins/ActiveSkill/Grid/PagingPrev.gif" /> <MasterTableView ClientDataKeyNames="id" DataKeyNames="ID"> <Columns>
770
771
Build and test the web service. Define the markup for the exam question control. Create the ExamManager client object. Create the UIManager client object. Add client code to the exam question control that will consume the new client objects. Code the FirstLoad() method in the code behind. Test taking an exam all the way through to navigation on to the "finish" control.
772
3. A design surface will display to allow the new item to be configured. From the View menu in Visual Studio, select Server Explorer. Right-click the Data Connections node and select Add Connection. In the Add Connection dialog that displays, click the Change button to display the Change Data Source dialog, select "SQL Server" and click OK to close the dialog. Back in the Add Connection dialog, enter the name of the server where the ActiveSkill database resides. For example, this might be "(local)" for your local SQL server or "(local)\SQLEXPRESS" if you have only SQLEXPRESS installed. Click OK to close the Add Connection dialog.
773
4. Now you should be able to open the list of tables that will include the ActiveSkill tables for Exam, Exam_Question, Question and Response.
774
5. Drag each of the tables from the server explorer to the design surface: Exam, Exam_Questions, Question and Response. Notice that the relationships are already defined between these tables and denoted by the arrows pointing between tables.
775
The relationships between tables allow much more interaction on the server than when they are serialized. When serialized the rules become stricter and the possibility of "Circular reference" errors are more likely. 6. Click on the relationship arrow between the Exam and Exam_Questions. In the properties window set the Parent Property Access to "Internal"
776
7. Click the Exam_Question to Question relationship arrow. Set the Child Property to "False". 8. Click the Question to Response relationship arrow. Set the Parent Property Access to "Internal". We will be looking at the data output by these entities in XML form as we test the web service. You may want to play with these relationships and see how they affect data. 9. Open Service1.asmx (added by default when we first created the web service project) and add the code below. Notice the "ScriptService" attribute. ScriptService lets the web service be consumed by a client script. This happens automatically, just by adding the attribute. We will see in a moment how a JavaScript proxy class is generated for us. Also notice how the LINQ code in the GetExam() method is brief and to the point. Older versions of this same code without LINQ were quite wordy in comparison. We end up with an Exam object that was defined for us when we created the Exam.DBML. [VB] Defining the Web Service [C#] Defining the Web Service using System.Configuration; using System.Data.Linq; using System.Linq; using System.Web.Services; using System.Web.UI.WebControls; namespace ActiveSkillWS { [WebService(Namespace = "http://www.telerik.com (http://www.telerik.com/)/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class Service1 : System.Web.Services.WebService { private string connectionString = ConfigurationManager.ConnectionStrings["ActiveSkillConnectionString"].ConnectionString; [WebMethod]
777
11. Click GetExam() to display apage that allows us to test the service manually. Enter a "3" (a sample exam that should be available in the database) and click the Invoke button.
778
If our web service is working properly, the data should display as an XML/SOAP response where we can see the Exam information, followed by Exam_Questions that in turn contain Responses. All of this information will be available to us on the client.
779
If the JavaScript is not displayed in the browser, save it locally for viewing. The commented version will look something like the code sample below. You can see that it registers a "ActiveSkillWS" namespace used to qualify the name of its one object "Service1". Service1 has some inherited behavior for defining the succeeded and failed callback functions, as well as path, timeout and user context properties. The GetExam() function is defined for us so that we simply need to call it from our JavaScript. Also be aware that if you don't manually include the JavaScript file in your application, ScriptManager will retrieve the file behind the scenes. [JavaScript] /jsdebug Output from the Web Service Type.registerNamespace('ActiveSkillWS'); ActiveSkillWS.Service1=function() { ActiveSkillWS.Service1.initializeBase(this); this._timeout = 0; this._userContext = null; this._succeeded = null; this._failed = null; } ActiveSkillWS.Service1.prototype={ _get_path:function() { var p = this.get_path(); if (p) return p; else return ActiveSkillWS.Service1._staticInstance.get_path();}, GetExam:function(id,succeededCallback, failedCallback, userContext) { /// <param name="id" type="Number">System.Int32</param> /// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param> /// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param> /// <param name="userContext" optional="true" mayBeNull="true"></param>
780
781
</fieldset> 4. In the designer, add a RadGrid inside the FieldSet tag with ID property "gridQuestion", AutoGenerateColumns set to "false", EnableViewState set to "false"and GridLines set to "None". 5. Set the MasterTableView properties NoMasterRecordsText to "", TableLayout to "Fixed"and ShowHeader to "false". 6. Add the following columns using the Columns collection editor or directly in the markup:
A GridBoundColumn with DataField "ID" and Visible equal to "false". A GridCheckBoxColumn with DataField "Correct" and Visible equal to "false". A GridTemplateColumn with DataField "UserChoice" and UniqueName "UserChoice". In the ItemTemplate for the column add a single standard ASP.NET Checkbox control with ID "cbUserChoice". Set the columns HeaderStyle.Width to "60px". A GridBoundColumn with DataField "HTML".
OnCommand to "ClientCommand". OnRowDataBound to "RowDataBound". [ASP.NET] Markup for the Grid <telerik:RadGrid ID="gridQuestion" runat="server" AutoGenerateColumns="False" EnableViewState="False" GridLines="None"> <MasterTableView NoMasterRecordsText="" ShowHeader="false" TableLayout="Fixed"> <Columns> <telerik:GridBoundColumn DataField="ID" UniqueName="ID" Visible="False"> </telerik:GridBoundColumn> <telerik:GridCheckBoxColumn DataField="Correct" UniqueName="Correct" Visible="False"> </telerik:GridCheckBoxColumn> <telerik:GridTemplateColumn DataField="UserChoice" UniqueName="UserChoice">
782
The constructor passes in the examID. The exam id originates from the TakeExamChoose.ascx control, was passed to the FirstLoad of the TakeExamQuestion.ascx control and placed to the "examIDField" hidden field. The hidden field value is retrieved just before ExamManager is constructed. The constructor also passes functions to handle the OnLoaded and OnFinish events of this object. OnLoaded fires just after the web service returns with its data. OnFinish fires when we run out of questions and the user tries to navigate to the next question. This object descends from "Sys.Component" (see the registerClass() method at the end of this code sample) and so has access to the event dispatching mechanism we use here to handleOnLoaded and OnFinish events. Once the call to initilizeBase() in the constructor is performed, the Sys.Component functionality is available. In the constructor fires the web service method "ActiveSkillWS.Service1.GetExam()", passing functions
783
The prototype where methods and properties are defined forExamManager has some simple properties for tracking the exam itself, the current question within the exam, the number of questions in the exam, and if we are currently on the last question. Navigation methods in the prototype, next() and back(), increment and decrement the current question index and check for the upper and lower bounds of the number of questions in the exam. The next() method has the additional responsibility of firing the OnFinish event if we're trying to navigate past the last question. The prototype finish() method iterates the questions and tallies the total and incorrect responses. This method also uses a ExamResults object (to be defined next) to store the results by question category. The finish() method serializes the results and builds a string of arguments that are ultimately sent to the TakeExamFinish.ascx control for display. [JavaScript] Defining the ExamManager Type.registerNamespace("ActiveSkill"); /* -- Exam Manager -- */ ActiveSkill.ExamManager = function(examID, onLoadedHandler, onFinishHandler) { // Sys.Component supports event dispatching mechanism ActiveSkill.ExamManager.initializeBase(this); this._exam; this._index = 0; this._onLoadedHandler = onLoadedHandler; this._onFinishHandler = onFinishHandler; ActiveSkillWS.Service1.GetExam(examID, this.serviceSuccess, this.serviceFail, this); } ActiveSkill.ExamManager.prototype = { /* properties */ get_exam: function() { return this._exam; }, get_index: function() { return this._index; }, get_question: function() { return this._exam.Exam_Questions[this._index].Question; }, get_count: function() { return this._exam.Exam_Questions.length; }, get_isLastQuestion: function() { return this._index == this.get_count() - 1; }, /* navigation methods */ next: function() { if (this.get_isLastQuestion()) {
784
785
786
The parameters passed to the constructor are simply references to page elements, e.g. "$get("<%= btnNext.ClientID %>")". Most of the action happens in two methods, refresh() and save(). refresh() updates the legend, label displaying the question and grid containing questions. Notice that we are binding the grid on the client side to our Exam object that was retrieved from the web service. The binding only takes three lines of code: retrieving the MasterTableView client object, setting the MasterTableView dataSource property and calling the MasterTableView dataBind() method. Sweet!
787
The save() method reverses the process described for refresh(). The tricky part here is that we need to get the template column check box that stores the user choices for each response.The key pieces to getting the value from a templated control are to first get the MasterTableView data items, get the data item fora given row, get the table cellthat contains our check box element by calling MasterTableView getCellByColumnUniqueName(), and finally setting propertiesin our data source to match the check box element checked property.Remember that for the call to getCellByColumnUniqueName to work, it must match theUniqueName property for the grid column.Also note the call to getElementsByTagName() that retrieves the check box element is a safer approach than assuming the check box will be present in a particular position. As it turns out, browsers will present these elements differently so checkboxCell[0] may contain the check box or it may be in checkboxCell[1]. [JavaScript] Defining the UIManager JavaScript Object Type.registerNamespace("ActiveSkill"); /* -- UI Manager -- */ // The constructor accepts and stores references to each page // element. ActiveSkill.UIManager = function(nextButton, backButton, questionLegend, questionLabel, grid) { ActiveSkill.UIManager.initializeBase(this); this._nextButton = nextButton; this._backButton = backButton; this._questionLegend = questionLegend; this._questionLabel = questionLabel; this._grid = grid; } ActiveSkill.UIManager.prototype = { /* -- properties -- */ get_nextButton: function() { return this._nextButton; }, get_backButton: function() { return this._backButton; }, get_questionLegend: function() { return this._questionLegend; }, get_questionLabel: function() { return this._questionLabel; }, get_grid: function() { return this._grid; }, /* -- methods -- */ // update page elements using the // data stored in the ExamManager object. refresh: function(examManager) { this.get_questionLegend().innerHTML = examManager.get_exam().Title;
788
789
790
For each row in the grid, the RowDataBound event setsthe "UserChoice" checkbox check based on the "UserChoice" value in the response. [JavaScript] Handling Grid Client Events function ClientCommand(sender, args) { // must assign this empty event handler to avoid "null object" error } function RowDataBound(sender, args) { // get the "UserChoice" checkbox var checkBoxCell = args.get_item().get_cell("UserChoice"); var cbUserChoice = checkBoxCell.getElementsByTagName("INPUT")[0]; // Set the checked property for the checkbox to // the underlying data value. if (cbUserChoice != null) { cbUserChoice.checked = args.get_dataItem()["UserChoice"]; } } 5. Add client functions to handle thenext and back button clicks. Both functions have essentially the same structure where the UIManager save() function is called to retrieve the current user choices, the ExamManager next() or back() methods are called to perform the navigation through the exam and the UIManager refresh() method is called to bind to the new question data. [JavaScript] Responding to Next and Back Button Clicks function goNext() { window.uiManager.save(window.examManager); window.examManager.next(); window.uiManager.refresh(window.examManager); } function goBack() { window.uiManager.save(window.examManager); window.examManager.back(); window.uiManager.refresh(window.examManager); }
791
792
Gotcha! If there are errors indicating the web service is not found, first verify that you can access the web service manually using the browser. Then verify this same path is used in a ScriptManager Reference element. The ScriptManager is kept on the UserHome.aspx page and will look something like this: <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="http://localhost/ActiveSkillWS/service1.asmx" /> </Services> <Scripts> <asp:ScriptReference Path="~/scripts/DynamicControl.js" /> <asp:ScriptReference Path="~/scripts/ExamManager.js" /> <asp:ScriptReference Path="~/scripts/UIManager.js" /> </Scripts> </asp:ScriptManager>
35.5 Summary
In this chapter you built functionality for the central purpose of the application, the taking of exams. The work was heavily weighted to the client where you consumed a web service to bring back the exam data, used your own JavaScript objects to encapsulate the exam, navigation through the exam and to summarize the exam results. You bound exam responses directly to the RadGrid using client code only. You also used LINQ to SQL within the web service to consume the Exam database data.
793
36.1 Objectives
Become familiar with RadChart by building a simple chart with static items and another basic chart using bound data. Take a tour of the basic elements of each RadChart and the available types of charts. Learn how designer interface tools help organize RadChart capabilities. Learn about some of the latest RadChart features. Create chart series and chart series items programmatically. Learn the specifics of data binding in RadChart. Learn how to handle RadChart server-side events. Learn how zooming and scrolling is performed in RadChart. Also learn how to perform zooming and scrolling in client-side code. Learn how image maps are created in RadChart and how an image map can be used to create a drill-down chart.
36.2 Introduction
RadChart is a powerful business data presentation tool that can show your data off with striking impact. RadChart comes with many customizable chart types and skins to tailor the behavior and look of each chart. You can choose fine-tune control over all aspects of your chart or use the automatic layout, automatic text wrapping and intelligent labeling functions to handle the details. At design time you get quick access to critical properties with the Smart Tag, convenient groups of important properties in the RadChart wizard, or control all RadChart settings from the Properties Window. The focus of this chapter will be in organizing the many capabilities and properties of this rich control so that you can get maximum use out of it from the outset.
794
Gotcha! Gotcha! At the time of this writing, if you are using IIS7 Integrated Mode, you need to add a handler manually to the <system.webserver> "handlers" element of the web.config file: <system.webServer> <handlers> <add name="ChartHandler" path="ChartImage.axd" verb="*" type="Telerik.Web.UI.ChartHttpHandler, Telerik.Web.UI" /> ... If you are using the internal web server, there shouldn't be a problem.
795
9. Repeat the Add Item steps to add 3 new items. Replace the properties for the three new items as follows:
Label: Produce, YValue: 7500 Label: Poultry, YValue: 9000 Label: Grains, YValue: 11200
796
10. Click OK to close the ChartSeriesItem Collection Editor. 11. Click "Series 2" in the ChartSeries Collection Editor. 12. Click the Remove button to remove Series 2. 13. Click the OK button to close the ChartSeries Collection Editor. 14. The chart will display the new data using the default formatting.
797
4. In the Properties window, set the AutoLayout property to "true". 5. Press Ctl-F5 to run the application. Notice that the AutoLayout feature of RadChart has positioned the labels on the Y axis (along the left side) and the legend ("Sales", on the right side of the chart). The chart title "Category Sales" should appear at the top of the chart.
798
799
In the Choose a Data Source Type page, choose "Database". Click the Next button to continue. In the Choose Your Data Connection pageselect the NorthwindConnectionString from the drop down list. Click the Next button to continue. In the Configure the Select Statement page, choose the"Specify a custom SQL Statement or stored procedure" radio button. Click the Next button to continue. In the Define Custom Statements or Stored Procedures page, enter the following SQL to the SELECT tab and click Next to continue. [T-SQL] Defining the Select SELECT TOP (10) ProductName, ProductSales, CategoryName FROM [Sales by Category] order by ProductSales desc
4. Still in the Data tab of the wizard, set the Y values drop down list to "ProductSales" and the X-Axis to "CategoryName". In a horizontal bar chart, the X-Axis will list the category names from top to bottom on the left hand side of the chart.
800
6. In the Labels, Legend & Title tab, set the Series Labels to "ProductSales" from the drop down list,deselect the Legend Visible check box. Set the Title Text to "Top 10 Product Categories"
7. Click the OK button to close the wizard. 8. In the Properties window set the AutoLayout property to "true". 9. Press Ctl-F5 to run the application. Notice that the labels on the X-axis are arranged from top to bottom on the left hand side in this horizontal layout. If the layout were vertical, the labels would be listed along the
801
RadChart Basics
Charts are composed of a hierarchy of elements. Many of the elements are common across all chart types. Take a look at the figure below to see some of the main chart elements, particularly the Plot Area, Chart Series, Chart Series ItemsandAxis.
802
Chart Background
The background of the chart is the outermost rectangle that encloses all other elements of the chart. It stretches for the whole width and length of the output image of the chart.
803
ActiveRegion: contains properties for HTML Attributes, Tooltip and URL. The ActiveRegion property is found throughout the chart control and can be used to create links that can be clicked to navigate the page to web sites. The properties set as below would let the user click the chart title and navigate to the Wikipedia web site. Hovering the mouse over the title would display the tool tip.
Appearance: This is an extensive property, also found attached to other properties throughout the chart. The exact makeup of Appearance changes depending on the context you find it in. Appearance lets you customize all the visual aspects of the chart element you're working with, such as layout, dimensioning, positioning, fill, background images, font colors and borders. The appearance properties for the ChartTitle are shown below. Here we're setting the RotationAngle to -20.
You can see the effect where the title is rotated 20 degrees to the left:
Marker: Controls a small graphic for whatever area is being described, e.g. title, legend, etc. By default the marker is not visible. Notice that the Marker property has it's own ActiveRegion and Appearanceproperties nested within.In the example below we've set the Figure property to "Star3" and the Visible property to true.
804
These property settings place a small rightward-pointing graphic to the left of the title.
TextBlock: lets you fine-tune the appearance of the text, the visibility of the text and the text string itself. In the example below we add a border set to the AliceBlue color.
The TextBlock.Appearance.Border property setting was applied to the ChartTitle to get this appearance:
805
Plot Area
The plot area is the working rectangular area between X and Y axes where data is displayed. This property isa major jumping off point for configuring the axis of the chart.
The size of the plot depends on the chart background size and the chart margins, which define the distance between the border of the plot area and the border of the chart background.
806
The PlotArea DataTable displays a spreadsheet style table of the data in the chart, typically just below the chart itself. You can see in the this screenshot that the data for both series is displayed in the table at the bottom of the chart.
The PlotArea EmptySeriesMessage is a predefined message that displays in the PlotArea when there is no series data defined for the chart. MarkedZones are areas in the background of the chart that can be defined, labeled and filled. MarkedZones are used to highlight or group areas on the chart and by default display behind the chart series. You can create any number of members for the MarkedZones collection and each marked zone is defined by starting and ending X and Y value pairs. There are two marked zones displayed in the screenshot below that delineate extreme high and low temperatures.
807
Chart Series
Series contains a set of data points to be drawn on the chart. This set of points contains related data. Each series can be represented by a chart type. Pie charts use only a single series. For other chart types there is no limitation to the number of series or items within each series. The screenshot below shows two series named "Internet" and "WholeSale" defined within the ChartSeries Collection Editor.
Use "#Y" or "#X" to display numbers from the X or Y axis respectively Use "#%" for a percentage of the total sum (of all items). Use "#SUM" to display the total of all items. "#STSUM" displays the sum of a stacked series.
808
"#SERIES" displays the series name. "#ITEM" displays the item name. You can also use standard numeric format strings. Use curly brackets to contain the formats. For example, you can display Y values as currency by setting DefaultLabelValue to "#Y{C}".
Series Items
Each chart series item encapsulates a single data point within a chart series. For simple charts along a single axis, you can populate the YValue property only. Use the XValue property to add a second data dimension. For example, the Y values could represent "Sales Volume" and the X values might show time periods or geographic regions. The meaning of the XValue2 and YValue2 properties vary depending on the type of chart. For example XValue2 and YValue2 are used by Gantt type to indicate a period of time and the Bubble chart type to show amplitude of data.
Stacked Bar Stacked Bar charts are used to compare contributions of values to a total across categories.Use the Stacked Bar chart when you need visibility to the combined values for each category.
809
Area The Area chart consists of a series of data points joined by a line and where the area below the line is filled.Area charts are appropriate for visualizing data that fluctuates over a period of time and can be useful for emphasizing trends.
Stacked Area The Stacked Area chart is a variation of the Area chart that display trends of the contribution of each value over time (or across categories). The areas are stacked so that each series adjoins but does not overlap the preceding series. Area charts are appropriate for visualizing data that fluctuates over a period of time and where the entire area for all series data must be visible at one time.
Stacked Area 100% Stacked Areas 100% charts are a variation of Stacked Area charts that present values for trends as percentages, totaling to 100% for each category. Use this chart type to visualize data that fluctuates over a period of time and where the relationship between values in a category is more significant than the amounts.
Pie The Pie chart shows slices representing fractional parts of a whole.
Gantt Gantt charts, also known as Time charts, display separate events as bars along a time scale.These charts are often used for project/time planning, where data can be plotted using a date-time scale or other numeric scale.
The Bezier chart displays a series of points on a curved line. Two "control points" determine the position and amount of curvature in the line between end points. The Bezier chart is often used for data modelling by taking a limited number of data points and interpolating or estimating the intervening values. Bezier
810
Spline Spline charts allow you to take a limited set of known data points and approximate intervening values.The Spline chart, like the Bezier, is often used for data modelling by taking a limited number of data points and interpolating or estimating the intervening values.
Bubble The Bubble chart is an extension of the Point chart but each point can be a circle or oval of any size or dimension. The bubble size may be used to convey larger values.The Bubble chart is often used for scientific data modeling or financial data.
Spline Area The Spline Area chart type defines one or more spline curves and fills in the area defined by the spline.This chart type can also can be used for data modelling in that it takes a limited number of data points and interpolates the intervening values.
Stacked Spline Area The Stacked Spline Area chart is a variation of the Spline Area chart. The areas are stacked so that each series adjoins but does not overlap the preceding series. Also can be used for data modelling in that it takes a limited number of data points and interpolates the intervening values. This chart type allows the entire surface area for all sequences to be displayed at one time. Stacked Spline Area 100% The Stacked Spline Area 100% chart is a variation of the Spline Area chart. The areas are stacked so that each series adjoins but does not overlap the preceding series and where the combined total for each category is 100 percent.The Stacked Spline Area 100% chart can also can be used for data modelling in that it takes a limited number of data points and interpolates the intervening values. This chart type allows the entire surface area for all sequences to be displayed at one time. Use this chart type when the relationship between values in a category is more significant than the amounts. Point or "Scatter" charts are used to show correlations between two sets of values. The Point chart is often used for scientific data modeling or financial data. The Point chart is typically not used used with time dependent data where a Line chart is more suited. Point
811
Line The Line chart type displays a set of data points connected by a line.A common use for the line chart is to show trends over a period of time.
CandleStick The CandleStick chart combines bar and line chart styles to show a range of value movement over time. Dark colored bars show downward trends, light colored bars show upward trends and the line through the center (the "wick") shows the extreme high and low values.Use this chart type to visualize price or currency fluctuations. Typically this chart is used to analyze stock prices or currency changes.
Stacked Line
Stacked Spline The Stacked Spline chart, line the Stacked Line, lets you have multiple series of Y values. It can take a limited number of data points and interpolate the intervening values.
812
Layout
At the top of the Smart Tag in the Layout section, you can set the Width and Height of the chart as a whole.
Appearance
Below the Layout area, you can use the Appearance section to quickly set the
Title Text Chart Series Orientation to Horizontal or Vertical from the drop down list. Default Chart Type to one of the chart types in the drop down list, i.e.Bar, Pie, Line or any of the types we reviewed in the Getting Started section. Skin can be set from the drop down list to quickly style the entire look of the chart.
Data
You can bring up the Chart Series collection editor from the ellipses if you want to statically define series and items directly at design time. If you want to bind data, select a data source from the drop down list. If no data sources exist in the project yet, select "<New Data Source...>" from the drop down list. Once a data source is configured and selected, two additional links are displayed in this area, "Configure Data Source" and "Refresh
813
Setting
From the Setting section you can choose a Chart Image Format from the drop down list. Most popular formats are supported includingMemoryBmp, Bmp, Emf, Gif, Jpeg, Png, Tiff, Exifand Icon. A link to the Chart Wizard lets you execute the wizard dialog for settings that are more detailed than the Smart Tag, but much smaller than the total number of properties available from the Properties window.
Chart Wizard
The RadChart Wizard helps you traverse the many properties of RadChart by providing the most commonly used properties in an intuitive way. The wizard can help you quickly set up the basic structure of your chart. The Wizard functions are arranged in tabs:
Type Tab
The Type tab lets you quickly choose the chart type by providing visual cues to what each type looks like. Here you can also choose the chart orientation.
Data Tab
The Data tab brings together the Series, Series Item, Axis labels and data binding to a single screen. Here you can add data points to your chart manually or by binding to data sources.
814
Group Column
The Group Column appears on the upper right side. Select a column name from a bound data source to group by that column data.
Series
Use the Series area of the tab to add, delete and reorder chart series elements using the list box provided. Use the plus and minus buttons to add or delete a series element. Use the up and down arrows to move a series element up or down in the list. For each selected series element in the list box you can provide a name and select from the list of chart types. If you bind to a data source the Databind Series Elements portion will be enabled and allow you to choose column names for your labels and values from the drop down lists provided. When you bind to a data source the Series list box will be populated automatically with a series for each numeric column in the data source. If you need to fine tune the behavior or appearance of a series in more depth than the Data tab provides, use the RadChart Series property in the property window.
Series Items
For each series you select in the Series area list, you can add, edit, delete and reorder entries. Use the plus and minus buttons to add and delete series items. Use the up and down arrows to move series items up or down in the list. For each item you can set the Name, Label and X and Y Values. X2 and Y2 values are enabled for Gantt
815
Axis Labels
This section lets you choose between binding to a column in the data source and using the column data to populate the labels along an Axis. Click the Add Labels Manually link to navigate to the Axis tab.
Skin Tab
The RadChart Skin property lets you apply a coordinated set of style changes to all the chart visual aspects at one time. The Skin tab lets you visually inspect how a chart might look with a given skin. The skins displayed reflect the current chart type.
816
Series Labels
This section lets you set label properties for a series name selected in the Series drop down list. Uncheck the Visible box to hide series labels. Enter a value between 0 and 360 to the Rotation entry to rotate all series labels at one time. Positive Rotation values rotate the labels clockwise, negative values rotate the labels counter-clockwise. Positive Distance values move the labels away from the chart series items.
Legend
Un-select the Visible check box to hide the legend. Use the Marker drop down to select from a predefined list of shapes, e.g. Cross, Diamond, Ellipse, Rectangle, etc.Use the Alignment drop down to move the legend position between None, Left, Top, Bottom, Center, TopRight, TopLeft, BottomRight and BottomLeft.
Title
The Title section lets you set the text andtoggle visibility of the chart title.Use the Alignment drop down to move the title position between None, Left, Top, Bottom, Center, TopRight, TopLeft, BottomRight and BottomLeft.
Axis Tab
From this tab you canselect an axis from the drop down list at the top of the page. Properties you modify will be retained for the selected axis. Use the Copy Settings From button to replicate settings from another axis.
817
Visual Properties
The Visual Properties section of the page controls properties for the axis as a whole. Uncheck the Visible checkbox to hide the entire axis (including labels and tick marks). The Axis Title text populates a single label that appears for the axis as a whole. Use the Alignment property to place the axis label in a predefined position, e.g. Left, Right, Top, Bottom, Center, TopRight, TopLeft, BottomRight, BottomLeft. Un-check Show Ticks to hide the axis tick marks. Un-check Show Labels to hide the axis labels (but not the Axis Title). The Value Format drop down list automatically formats axis labels as various kinds of dates, times, percentages, numbers and currency. Visible Values can be All, Positive or Negative values. Rotation is used to rotate the axis label text. Positive numbers spin the labels clockwise, negative numbers counter-clockwise.
Axis Labels
Turn off Auto Scale if you want to provide custom axis labels instead of the default numeric values. Turning off Auto Scale also lets you use the Min, Max and Step values. Enter Min and Max values to control the number of series items to be displayed along that axis. Enter a Step value to control the interval between axis labels. If Auto Scale is off you can use the provided list box to add, delete and reorder axis label items manually. By selecting any one of the axis label values in the listbox you can assign a text label. Click the Bind Axis Labels to Database link to navigate back to the Data tab.
818
Visual Properties
Check Visible to display the chart data table. By default this is unchecked. Select Draw Type from the drop down list to control the general size and positioning of the chart:
Select AutoSize to have each cell size to the data inside of it. PlotAreaRelative places each cell just below the chart series item it represents. CellFixedSize and TableFixedSize fix the size of the cells or table irrespective of the data it contains.
Alignment
Use the Align drop down list to place the chart data table in a predefined position (e.g. Top, Bottom, BottomRight, etc.) To place the data table at exact coordinates, un-check Auto and enter values for X and Y.
Properties Window
At design time, you can use the Properties Window to configure almost every aspect of the chart.You will need to build a mental map ofhow the critical properties arearranged. At the top level the critical properties are ChartTitle, DataSourceID,Legend, PlotArea and the Series collection. Within the Series collection are Items collections that define the individual data points in the series. Other helpful properties: IntelligentLabelsEnabled: For charts that have many data points or data points with values close to one another, labels tend to collide making readability a problem. The Intelligent Labels feature of RadChart automatically re-aligns labels making each labeled value stand out clearly. UseSession and TempImagesFolder: If UseSession is true (default value), the chart is being streamed through the session. If UseSession is false, the images can be streamed to the path specified in TempImagesFolder ("~/Temp" by default). Gotcha! If you are using the chart in a web farm, make sure that the session state is either StateServer or SQLServer. If this is not so, the chart image can be generated on one server and the image request
819
Empty Values
RadChart automatically approximates missing values between known data points, simply by setting the Empty property true on any chart series item. This works for bar, line and area based chart types. You also have complete control over the visual style of empty values. The empty value style can be articulated separately from the style for the main values.
Scale Breaks
The ScaleBreaks feature allows you to "break off" large chunks of the axis so that graphs with large amplitude are easier to read. ScaleBreaks are available for both YAxis and YAxis2 properties of the PlotArea. You can tailor the maximum number of breaks, the minimum interval between data points before a break can occur, the visual size of the breaks and the visual style of the breaks.
820
Multi-Line Labels
Labels in RadChart can appear on multiple lines. For example, the property editor for TextBlock.Text properties allows you to hit the enter key to start a new line. Press control-enter to accept the text and close the property editor.
Strict Mode
821
Logarithmic Y-Axis
RadChart's Y-Axis now supports logarithmic mode. This is convenient when you would like to display rapidly increasing values. Set theYAxis or YAxis2 IsLogarithmic property (false by default) to true to enable this behavior. The LogarithmBase property (10 by default) can be increased to further compress the presentation of values.
822
823
[VB] Adding a Chart Series and Items Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) RadChart1.AutoLayout = True ' Create the series and assign the ChartSeriesType RadChart1.Series.Clear() Dim chartSeries As New ChartSeries("Average Temperatures", ChartSeriesType.Bar) ' Define the items in the series chartSeries.AddItem(5) chartSeries.AddItem(1) chartSeries.AddItem(-1) chartSeries.AddItem(-5) chartSeries.AddItem(-7) ' add an empty item Dim isEmpty As Boolean = True Dim item As New ChartSeriesItem(isEmpty) chartSeries.AddItem(item) chartSeries.AddItem(-3) ' Add the series to the chart, chart to page. RadChart1.Series.Add(chartSeries) End Sub [C#] Adding a Chart Series and Items protected void Page_Load(object sender, EventArgs e) { RadChart1.AutoLayout = true; // Create the series and assign the ChartSeriesType RadChart1.Series.Clear(); ChartSeries chartSeries = new ChartSeries("Average Temperatures", ChartSeriesType.Bar); // Define the items in the series chartSeries.AddItem(5); chartSeries.AddItem(1); chartSeries.AddItem(-1); chartSeries.AddItem(-5); chartSeries.AddItem(-7);
824
You can find the complete source for this project at: \VS Projects\Chart\ServerSide1 1. Create an ASP.NET AJAX Web Application 2. Create a new ASP.NET Web Application and drag a ScriptManager from the Tool Box onto the Web page 3. From the Toolbox drag a RadChart component to the default web page. 4. Click the Smart Tag Add RadChart HTTP Handler to Web.Config link. 5. Begin coding the Page_Load handler by setting up thelabel and chart title. For the legend you need to shut off the Appearance.Position.Auto so that you can explicitly position the legend exactly where you want it. You could also have used one of the predefined positions, hidden the legend or set theAppearance fill to a transparent color so you could seethrough to the data points
825
826
[VB] Configuring the XAxis ' Configure the XAxis RadChart1.PlotArea.XAxis.AutoScale = False RadChart1.PlotArea.XAxis.AddRange(1, 7, 1) RadChart1.PlotArea.XAxis(0).TextBlock.Text RadChart1.PlotArea.XAxis(1).TextBlock.Text RadChart1.PlotArea.XAxis(2).TextBlock.Text RadChart1.PlotArea.XAxis(3).TextBlock.Text RadChart1.PlotArea.XAxis(4).TextBlock.Text RadChart1.PlotArea.XAxis(5).TextBlock.Text 8. RadChart1.PlotArea.XAxis(6).TextBlock.Text [C#] Configuring the XAxis
= = = = = = =
// Configure the XAxis RadChart1.PlotArea.XAxis.AutoScale = false; RadChart1.PlotArea.XAxis.AddRange(1, 7, 1); RadChart1.PlotArea.XAxis[0].TextBlock.Text = RadChart1.PlotArea.XAxis[1].TextBlock.Text = RadChart1.PlotArea.XAxis[2].TextBlock.Text = RadChart1.PlotArea.XAxis[3].TextBlock.Text = RadChart1.PlotArea.XAxis[4].TextBlock.Text = RadChart1.PlotArea.XAxis[5].TextBlock.Text = RadChart1.PlotArea.XAxis[6].TextBlock.Text =
9. Configure the YXis AxisMode to Extended so that there is a little more room at the top of the chart. Set the Text for the AxisLabel.TextBlock to "Temperature C" and the Appearance.Width to "3". [VB] Configure the YAxis ' Configure the YAxis RadChart1.PlotArea.YAxis.AxisMode = ChartYAxisMode.Extended RadChart1.PlotArea.YAxis.AxisLabel.TextBlock.Text = "Temperature C" [C#] Configure the YAxis // Configure the YAxis RadChart1.PlotArea.YAxis.AxisMode = ChartYAxisMode.Extended; RadChart1.PlotArea.YAxis.AxisLabel.TextBlock.Text = "Temperature C"; 10. Clear the chart Series collection to remove the default two series that show up at design time when you add the chart to the page. Create a new ChartSeries with name "Average Temperatures" andtype "Bar". Set the main color for the series Appearance FillStyleto "HoneyDew" and the secondary color to "Green". [VB] Add the Chart Series ' Create the series and assign the ChartSeriesType RadChart1.Series.Clear() Dim chartSeries As New ChartSeries("Average Temperatures", ChartSeriesType.Bar) chartSeries.Appearance.FillStyle.MainColor = System.Drawing.Color.Honeydew chartSeries.Appearance.FillStyle.SecondColor = System.Drawing.Color.Green [C#] Add the Chart Series
827
12. Add the code below to the end of the Page_Load event handler:Add a second series with name "Maximum Temperatures" and type "Line". Hide the labels by setting the series Appearance.LabelAppearance.Visible
828
[VB] Enhance the "Maximum Temperature" Data Points ' visually enhance the data points chartSeries2.Appearance.PointMark.Dimensions.Width = 5 chartSeries2.Appearance.PointMark.Dimensions.Height = 5
829
830
Data Binding
RadChart data binding works similarly to other RadControls in that you can bind the same basic types, consume the same data source controls and can assign either DataSourceID declaratively or DataSource (and call DataBind()) at runtime. The control-specific differences are in the properties used to specify what columns are bound to particular displays and behaviors in the chart.
The ChartSeries has a DataLabelsColumn property to define a column that will supply the text that displays next to each X Axis item. The XAxis also has this DataLabelsColumn property.
831
As the items are bound, the labels are formatted based on the ranges of values the data points fall within. [C#] Handling the ItemDataBound Event Protected Sub RadChart1_ItemDataBound(ByVal sender As Object, ByVal e As Telerik.Charting.ChartItemDataBoundEventArgs)
832
833
Data with columns "Year", "Quarter" and "Value" "Year" contains multiple rows for "2007" and "2008". The DataGroupColumn property is "Year".
...then there will be two series, one for "2007" and the second for "2008". A second RadChart property, GroupNameFormat, defines a format for the legend item. The format can have free text and can include two special words:
#NAME: denotes the group column name. #VALUE: denotes the group column value (it is the same for all the records shown in the same series).
The SQL below gets a sampling of Invoice data and brings back the CustomerID, ExtendedPrice and Quantity. [T-SQL] Selecting Invoice Data SELECT TOP (25) CustomerID, ExtendedPrice, Quantity FROM Invoices ORDER BY CustomerID The "ORDER BY" clause counts for group queries. If the data in the example above was unordered, you would get a group for the first few records of customer "ALFKI", then a few records for "ANATR", then perhaps another bar for the next few "ALFKI" customer again. In typical cases adding the ORDER BY clause will give you the results you expect. The screenshot below shows the DataGroupColumn set to "CustomerID". No series is set and the DataYColumn property of the series is not set. The actual values that shown in the bar are derived from the last numeric column in the datasource. In the figure below the "Quantity" data shows in the chart.
834
Gotcha! Don't define the series DataYColumn as it will take precedence over the group property settings.
Using the Year/Quarter/Value data mentioned above and if we set the GroupNameFormat to "#NAME: #VALUE", the legend will be "Year: 2007" and "Year: 2008". We can build this example by first creating a class to contain the Year/Quarter/Value, populating a generic list of these objects, setting the group properties and finally binding to the grid. You can find the complete source for this project at: \VS Projects\Chart\Grouping 1. Create an ASP.NET AJAX Web Application 2. Create a new ASP.NET Web Application and drag a ScriptManager from the Tool Box onto the Web page 3. From the Toolbox drag a RadChart component to the default web page. 4. Click the Smart Tag Add RadChart HTTP Handler to Web.Config link. 5. In the Page_Load, populate a generic List of Sales objects
835
836
Use the axis DataLabelColumn property to add meaningful labels to the data across the bottom of this chart. If we had a property/column "QuarterDescription" with values "Qtr 1", "Qtr 2"..., these can be used in place of the number 1, 2...
Server Events
Use the RadChart OnClick event to handle server postbacks caused by clicking on areas of the chart. The event handler returns "sender", i.e. the RadChart itself and ChartClickEventArgs. ChartClickEventArgs contains Element, that is, the chart element that was clicked. For instance, you can test if Element is Telerik.Charting.ChartTitle to see if the ChartTitle was clicked. You can also use the Element's ActiveRegion property to access the ToolTip and Url properties if you want to navigate based off the click.
837
ClientSettings
RadChart has a ClientSettingspropertywith sub properties thatcontrol zooming and scrolling. Zooming and Scrolling are disabled by default. Enable zoomingand scrolling by setting the ScrollMode property to a value other than None. The available ScrollMode values are None, XOnly, YOnly and Both.
The image below shows the zoom rectangle and the axis markers that help the user know what area is to be zoomed.
838
You can customize the zoom rectangle using the ZoomRectangleColorand ZoomRectangleOpacity properties. Thescreenshotabovesets the ZoomRectangleColor property to "Red" and the ZoomRectangleOpacity to .3 (making it slightly more opaque than the default .2). You can set ZoomRectangleOpacity from 0 (transparent) to 1 (completely opaque). The axis markers are controlled by AxisMarkersColor, set to "Purple" in the screenshot above, and AxisMarkersSize that controls the length of the axis marker line in pixels. You can hide axis markers by setting EnableAxisMarkers to "false".
Scroll Only
You can also use scrolling alone by explicitly disabling manual client-side zooming (RadChart.ClientSettings.EnableZoom = False). You can still provide XScale and YScale values on the serverside. For example, the markup below allows the user to see a chart that is scaled by 4, can scroll along the X Axis, but cannot zoom.
Client-Side API
Zooming and scrolling can be controlled completely on the client side so you can make your chart interact with other elements on your web page. After getting a reference to the RadChart client object you can call the following methods:
scroll(): programmatically scroll along both axis at one time or only along X or Y axis. Use the get_xScrollOffset() or get_yScrollOffset() methods to preserve the status quo. In the example code below, get_xScrollOffset() is usedto preserve the current X offset sothat the scroll only occurs along the Y axis. [JavaScript] Using the scroll() method var chart = $find("<%= RadChart1.ClientID %>"); chart.scroll(0.2, 0.3); // scroll to top-left corner chart.scroll(0, 0); // scroll to bottom-right corner chart.scroll(1, 1); // scroll only by XAxis chart.scroll(0.4);
839
zoom(): Zooming can be done along X and Y axis combined or only along X or Y axis. Similar to the scrolling example above, use the get_xScale() and get_yScale() methods to preserve the existing offsets. You can also pass additional parameters to zoom() so that after zooming you can scroll at the same time. [JavaScript] Using the zoom() method var chart = $find("<%= RadChart1.ClientID %>"); //scale XAxis by factor 3 chart.zoom(3); //scale XAxis by factor 3 and YAXis by factor 2 chart.zoom(3, 2); //scale only YAxis by factor 2 chart.zoom(chart.get_xScale(), 2); //scale XAxis by factor 3 and YAXis by factor 2 //scroll to bottom-right corner of the plotArea chart.zoom(3, 2, 1, 1);
zoomOut(): RadChart keeps a history of zooming actions. This method zooms out the current chart view to the previous scaling step and also restores the scrolled position. resetZoom(): Resets the scaling factors so that no zoom is applied.
840
36.8 How To
Creating Image Maps and Drill-Down
Image Maps
Image maps are visual areas within the chart that display tool tips. Clicking these areas automatically navigates the user to a URL.Image maps are implemented with the help of the ActiveRegion property that contains URL and ToolTip properties. You can assign the ActiveRegion URL property directly or use the ActiveRegion Click event and respond in server code. The ActiveRegion resolves to a standard HTML "<map>" tag that defines the area within the chart image that will respond to the mouse: [HTML] An HTML Fragment from the Rendered Chart <map id='imRadChart1' name='imRadChart1'> <area shape="poly" href="http://www.telerik.com (http://www.telerik.com/)" coords="176,168,247,167,248,199,227,226,198,236" alt="Sales"
841
The default page is setup where the chart Type is "Pie". The DefaultLabelValue property is "#ITEM" so that each slice is labeled with it's name.
842
Inside the Items collection for this series are three ChartSeriesItems, eachwith the ActiveRegion configured in a similar way. The Tooltip reads "Click for more info" and the Url is "Details.aspx?SalesType=Wholesale". The SalesType query string is specific to each chart series item.
The second page in the project (other than default.aspx) is Details.aspx. This page contains the usual ScriptManager and RadChart. In the Page_Load event hander, the query string is received and used to build the chart title. Some dummy items are created, but you can adapt this code to use the passed in query string in a "WHERE" clause that filters a data source. [VB] Configuring the Details RadChart Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not IsPostBack Then ' Get the sales type passed from the default page
843
844
36.9 Summary
In this chapter you built a simple chart with static items and also learned how to bind data to the chart. You took a tour of the basic RadChart elements as well as the types of charts that are available. You learned how to use the tools in the designer to help navigate the many RadChart capabilities. You learned some of the latest RadChart features, including zooming and scrolling. You created and configured many of the chart elements programmatically, including the chart series, items, legend and chart title. You learned how to bind to database data and respond to events on the server side.
845
37.1 Objectives
Build the TakeExamFinish.ascx User Control. Deserialize a JSON string into a server-side object. Configure a RadChart control and bind it to a generic List object.
Add DataSource
Add a SqlDataSource to the control with ID "dsCategory', use the ActiveSkillConnectionString for the ConnectionString property, set SelectCommand to "Skill_Category_SelectWhere" and SelectCommandType to "StoredProcedure". In the SelectParameters collection add a single parameter with Name "ID" and Type "Int32". The markup should look like the example below. [ASP.NET] Adding the DataSource <%--Data sources--%> <asp:SqlDataSource ID="dsCategory" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="Skill_Category_SelectWhere" SelectCommandType="StoredProcedure"> <SelectParameters> <asp:Parameter Name="ID" Type="Int32" /> </SelectParameters> </asp:SqlDataSource>
846
847
Gotcha! At the time of this writing, if you are using IIS7 Integrated Mode, you need to add a handler manually to the <system.webserver> "handlers"element of the web.config file: <system.webServer> <handlers> <add name="ChartHandler" path="ChartImage.axd" verb="*" type="Telerik.Web.UI.ChartHttpHandler, Telerik.Web.UI" /> ... 3. Also in the Smart Tag, enter these settings:
Width: 652 Height: 491 Title Text: Answers by category Chart Series Orientation: Vertical Default chart type: Stacked Bar Skin: DeepGray
4. In the Properties Window set the IntelligentLabelsEnabled property to "true". 5. In the Series collection editor, set the name of the first series to "Correct Answers" and the second series to "Incorrect Answers". The completed markup should look something like this example:
848
849
850
851
852
2. In theFirstLoad() methodadd code to store the the incoming arguments. The passPercent and title arguments are simple assignments to the "passPercent" numeric variable and the "title" string variable.The examResults is a serialized JSON string that must be Deserialized into object form before we can use it. The JavaScriptSerializer Deserialize() method takes care of this by converting the JSON string into a server-side ExamResults object. [VB] Storing Incoming Arguments Public Sub FirstLoad(ByVal args As Dictionary(Of String, String)) ' Store args information Dim passPercent As Double = Convert.ToDouble(args("passPercent")) Dim title As String = args("title") ' Retrieve the serialized JSON ExamResults client object and ' Deserialize into the server ExamResults object. Dim jss As New JavaScriptSerializer() Dim examResults As ExamResults = jss.Deserialize(Of ExamResults)(args("examResults")) '. . . End Sub [C#] Storing Incoming Arguments public void FirstLoad(Dictionary<string, string> args) { // Store args information double passPercent = Convert.ToDouble(args["passPercent"]); string title = args["title"]; // Retrieve the serialized JSON ExamResults client object and // Deserialize into the server ExamResults object. JavaScriptSerializer jss = new JavaScriptSerializer(); ExamResults examResults = jss.Deserialize<ExamResults>(args["examResults"]);
853
854
Test Exam
Press Ctl-F5 to run the application. Take a short exam multiple times to verify the output on the final page whenthe score is passing and failing. Check that the "Continue" or "Try Again" button navigates back to the TakeExamChoose.ascx control.
855
37.3 Summary
In this chapter you implemented the TakeExamFinish.ascx control. You deserialized a JSON string passed from the client into a server ExamResults object. You added HTML controls to display exam results and also added and configured a RadChart. You bound the RadChart to a generic List of objects and displayed the data in a stacked bar format with two series of data.
856
857
38.1 Objectives
Explore the features of the date, time, calendar and scheduler controls. Create simple applications to get familiar with the basic controls. Explore thedesign time interfaces, including the Smart Tag, Properties Window and Template Design surface. Explore principal properties and groups of properties where most of the functionality is found. Learn server-side coding techniques including the major server side objects, setting calendar special days, adding scheduler appointments, adding scheduler resources, scheduling recurrence and handling serverside events. Explore some of the client-side methods of the date, time, calendar client-side objects. Includes drilling down to the objects that make up the picker controls, controlling popups, and selected dates. Learn how to validate date and time entry. Learn to use scheduler templates.
1. Open the web.config file and add the following application setting to set the Skin for all RadControls in the application to "Sunset". [ASP.NET] Add the Telerik Skin Setting <appSettings> <!-- Sets the skin for all RadControls --> <add key="Telerik.Skin" value="Sunset"/> </appSettings> Be sure to not set the Skin properties for any of the controls. That includes making sure that tags like Skin="" and Skin="Default" do not exist in the markup. If the "Sunset" skin does not appear for one of the controls, check the markup for any instances of "Skin=xxx" and remove them. 2. In a new web application add a RadFormDecorator to the default page. 3. Open the Smart Tag and select Add ScriptManager from the context menu.
858
Open the Smart Tag and select Build RadTabStrip... Add three items to the tab strip with Text properties set to "Flights", "Cars" and "Search Results".
5. Drop a RadMultiPage control below the tab strip and configure the multi page:
Open the Smart Tag and click the Add PageView link two times for a total of three pages (there should be a default page there when the RadMultiPage is first added). Click on the page views and set their ID properties in the Properties window to "pvFlights", "pvCars" and "pvSearchResults".
6. Go back to the RadTabStrip and set the MultiPageID property to the RadMultiPage control's ID. 7. Add controls to the "pvFlights" page view:
Add a standard ASP Label control. Set the CssClass property to "radInput_Sunset" and the Text to "Departing:". Note: We're hijacking "radInput_Sunset" which is a CSS style that exists in the Sunset skin and suits our purposes. Add a RadDatePicker and set the ID property to "dpDepart". Add another standard ASP Label control. Set the CssClass property to "radInput_Sunset" and the Text to "Arriving:". Add a second RadDatePicker and set the ID property to "dpArrive". Add a standard ASP Button control and set the ID property to "btnFlights". Note: functionality for the buttons will be implemented in the upcoming section on server-side code.
Add a standard ASP Label control. Set the CssClass property to "radInput_Sunset" and the Text to "Pickup:". Add a RadDateTimePicker and set the ID property to "dtpPicker". Add another standard ASP Label control. Set the CssClass property to "radInput_Sunset" and the Text to "Drop Off:". Add a second RadDateTimePicker and set the ID property to "dtpDropoff". Add a standard ASP Button control and set the ID property to "btnCars".
Add a standard ASP Label control. Set the CssClass property to "radInput_Sunset" and the Text to "Results". From the HTML tab of the Toolbox add aDiv tag. Set the Style property to "float: left; margin:5px"". In the Div tag add astandard ASP Label control. Set the CssClass property to "radInput_Sunset" and the Text to "Start:". Add a RadCalendar and set its ID property to "calStart" and the Enabled property to false. Also set the
859
Add a standard ASP Label control and set the ID property to "lblStart". Set the CssClass property to "radInput_Sunset" and the Text to "". From the HTML tab of the Toolbox add aDiv tag. Set the Style property to "float: left; margin:5px"". In the Div tag add astandard ASP Label control. Set the CssClass property to "radInput_Sunset" and the Text to "End:". Add a RadCalendar and set its ID property to "calEnd" and the Enabled property to false. Also set the PresentationType propertyto"Preview".Open the SelectedDayStyle property to set BorderColor to "LightBlue" and BorderStyle to "Dotted". Add a standard ASP Label control and set the ID property to "lblEnd". Set the CssClass property to "radInput_Sunset" and the Text to "". From the HTML tab of the Toolbox add aDiv tag. Set the Style property to "clear: both". The "clear:both" style setting lets us move the elements that come later to the following line. Failing to clear will display the next elements to the right of the calendars, rather than below the calendars.
In the Div tag, add a standard ASP Button control with ID property set to "btnContinue" and Text as "Continue".
10. In the code-behind for the page add the code below to the Page_Load event handler. This code sets the minimum and maximum dates for both the departure and arrival RadDatePicker controls. [VB] Setting the Min and Max Dates Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not IsPostBack Then ' set both start and end date limits dpDepart.MinDate = DateTime.Today dpArrive.MinDate = DateTime.Today dpDepart.MaxDate = DateTime.Today.AddDays(21) dpArrive.MaxDate = DateTime.Today.AddDays(21) End If End Sub [C#] Setting the Min and Max Dates
860
RadCalendar has a set of navigation controls and titling along the top. Row and column headers are displayed along the left side and top, with a View Selector button showing at the apex of row and column headers. The View Selector lets the user select all days in the view at once.
861
The user can also click the Title and Navigation Popup area to display the "Fast Navigation" popup.
Smart Tag
The RadTimePicker, RadDateTimePicker, RadDatePicker and MonthYearPickerhave similar Smart Tags with some small differences. All have the standard Ajax Resources, Skin selection, and Learning center sections.
862
All contain the ability to enable AutoPostBack, but RadDateTimePicker allows you to choose which controls trigger the post back:
863
The RadDateTimePicker and RadTimePicker controls also let you Edit Templates to control the exact look and feel of each cell that displays the time, an alternating template so you can visually differentiate closely packed times for a clearer user interface, header and footer templates.
The RadCalendar Smart Tag lets you toggle the AutoPostBack and the ability to MultiSelect days on the calendar. The Configure Special Days link jumps you to the RadCalendarDay Collection Editor dialog. The Edit Templates link lets you create customized headers and footers for the calendar.
864
You can also share controls to be used by multiple pickers by setting the SharedCalendarID and SharedTimeViewID properties. The SharedCalendarID points to the ID of a RadCalendar control which may also be used stand-alone, but the SharedTimeViewID points to a special RadTimeView control available on the ToolBox that cannot be used stand-alone.
You can limit the user selection within a range of dates by setting the MinDate and MaxDate properties. These
865
866
Layout, e.g. DefaultCellPadding, DefaultCellSpacing Specific appearance properties for the calendar as a whole, e.g. BackColor, BorderStyle, etc., as well as a CssClass property to allow the calendar to be styled. Properties suffixed with "Style" (e.g. CalendarTableStyle, FastNavigationStyle, etc). Each of these "Style" properties has sub-properties that define specific appearance (i..e. BackColor, BorderStyle, etc) or let you define a CssClass. The Skin and skin related properties.
How do these appearance properties for the calendar as a whole, "Style" properties and Skins work together? To get an idea, take a look at the screenshot below where the calendar Skin is set to "Sunset", the BackColor to "Red", CalendarTableStyle BackColor to "Orange" and the DayStyle BackColor to "Yellow". You can see that the calendar heading retains the "Sunset" skin, but the other visual aspects of the calendar have been overridden by the more specific appearance properties.
You may have noticed the PresentationType property in the Appearance group. Setting the PresentationType property from "Interactive" to "Preview" determines how the Calendar will handle layout and user interaction. Using the "Preview" setting prevents the user from selecting a date, but the user can still navigate in the calendar. In the past you might have set Enabled to false, but this prevents the user from navigating. The SpecialDays property is a collection of RadCalendarDay objects that can be styled separately from the other calendar days. In fact, each special day can be styled individually by using the ItemStyle property to set BackColor, CssClass etc., or can use its TemplateID to point at a template.
867
Templates for special days are contained in the CalendarDayTemplates collection property. You can populate these templates directly within the markup.
Calendar Behavior
Behavior properties include an Orientation property that can be RenderInRows (the default) or RenderInColumns. You should also note the EnableMultiSelect that defaults to true. The screenshot below was taken after Orientation was set to RenderInColumns and EnableMultiSelect was left at its default of true.
Managing Dates
This group of properties controls the layout of days, what dates are visible, the valid dates that can be selected and the actual dates that are selected.
868
FirstDayOfWeek is an enumeration of Sunday through Saturday that controls the layout of days in the calendar. FocusedDate makes the specified date visible in the calendar when SelectedDate has not been set. Note that FocusedDate does not actually select the date or make any appearance changes to the date. At the time of this writing, FocusedDateColumn and FocusedDateRow are marked to be obsolete in future versions. RangeMinDate and RangeMaxDate set the lower and upper boundaries of dates that may be selected. Dates outside this range will be disabled and the user will not even be able to navigate outside views in the range.
View Settings
The calendar is presented as a "single view" by default where only a single month shows. Instead you can create a "multiple view" showing multiple months. The General View Settings and MonthView Specific Settings control the layout and appearance for these views.
To get multiple months shown within the calendar, either set the MonthLayout property to any of a number of pre-defined dimensions (e.g. 7 columns x 6 rows, 14 x 3, 21 x 2, 7 x 6...) or you can specify your own by setting the MultiViewColumns and MultiViewRows properties to values larger than the default of "1". The screenshot below shows a whole year of months where MultiViewColumns is set to "4" and MultiViewRows to "3".
869
Likewise you can control the dimensions of a single month view using the SingleViewColumns and SingleViewRows properties. In the screenshot below, SingleViewColumns is set to "14". Notice that only the January days are highlighted even though the days extend into February and March.
EnableNavigationAnimation is false by default but when enabled produces a very cool effect that "slides" between months when the navigation buttons are clicked. In the Monthview Specific Settings you can use a standard format character in the CellDayFormat property. By default this value is "%d", i.e. it outputs an integer number with no leading zeros. The screenshot below uses the format string "dd" to include a leading zero:
870
ShowOtherMonthDays when set to false hides any days that are not part of the month being viewed. UseColumnHeadersAsSelectors and UseRowHeadersAsSelectors are both true by default and let your user select entire columns or rows with a single click.
Navigation
The Navigation properties control the behavior, visiblity, layout and text for the navigation buttons along the top of the calendar.
Titling
Titling properties handle the formatting and layout of the title area at the top center of the calendar.
871
RadDateInput is the class for the input area of RadDatePicker, RadTimePicker, and RadDateTimePicker. It handles the formatting and parsing of date and time strings, and has a number of its own properties, methods, and events. RadDateInput is one of the standard RadInput controls. CalendarPopupButton and TimePopupButtonare the classes for the popup buttons that display the calendar on RadDatePicker and RadDateTimePicker and the time view popup in RadTimePicker and RadDateTimePicker. RadMonthYearPopUpButton is the class for the button that displays the MonthYearView popup in the MonthYearPicker control. RadTimeView is the class for the popup time view used by RadTimePicker and RadDateTimePicker. RadTimeView is also available in the toolbox so that a single instance can be shared among multiple RadTimePicker and RadDateTimePicker controls. MonthYearView is the class for the popup monthyear view used by the RadMonthyearPicker. DataListItem is the standard System.Web.UI.WebControls.DataListItem class. The RadTimeView control uses this class for each of the items it displays. It can be accessed through the DataList property, and is also available as the Item property of the eventArgs of the ItemCreated and ItemDataBound events. DataListItem descends from WebControl.
RadCalendarDay maps a date value to its corresponding visual settings and a number of boolean properties that represent its status (weekend date, disabled, selected, and so on). This class is used in the Day property of the eventArgs of the DayRender event, and for elements in the SpecialDays collection. CalendarView represents the current view of the calendar. It can include links to child views if the calendar is in multi-view mode. This class is also used in the OldView and NewView properties of the eventArgs of the DefaultViewChanged event. MonthView is a descendant of CalendarView that represents the view information for a single month. The View property of the eventArgs in the DayRender event is of MonthView type. It is also the type for the CalendarView property when the calendar is in single-view mode. TableCell is the control class for a cell in the day matrix. The Cell property within the DayRender event args is of this type. RadDate is a wrapper for System.DateTime. It is used for persisting DateTime values in collections such as the SelectedDates property. DayTemplate is the type for each element of the CalendarDayTemplates property. DayTemplate implements the ITemplate interface.
SelectedDateChanged: RadDatePicker and RadDateTimePicker surface a SelectedDateChanged event that occurs when the user changes the value of the control, either when the input area loses focus after the user has typed a new value, or when the user selects a new value in the popup calendar or time view control. The event passes SelectedDateChangedEventArgs as a parameter that contains two DateTime properties NewDate and OldDate. Don't forget that this event will not fire unless there's a postback, so you'll need to set the AutoPostBack, AutoPostbackControl (when using RadDateTimePicker)or trigger a postback through some other means. ItemCreated and ItemDataBound: Controls that use a RadTimeView, i.e. RadTImePicker and
872
[CSS] Alternating Row Styles <style type="text/css"> .FirstRowCss { background-color: LightGreen; } .FirstAlternatingRowCss { background-color: Lime; } </style> [VB] Handling the ItemCreated Event Protected Sub RadDateTimePicker1_ItemCreated(ByVal sender As Object, ByVal e As Telerik.Web.UI.Calendar.TimePickerEventArgs) If e.Item.ItemType = ListItemType.Item Then e.Item.CssClass = "FirstRowCss" End If If e.Item.ItemType = ListItemType.AlternatingItem Then e.Item.CssClass = "FirstAlternatingRowCss" End If End Sub [C#] Handling the ItemCreated Event protected void RadDateTimePicker1_ItemCreated(object sender, Telerik.Web.UI.Calendar.TimePickerEventArgs e) { if (e.Item.ItemType == ListItemType.Item) { e.Item.CssClass = "FirstRowCss"; } if (e.Item.ItemType == ListItemType.AlternatingItem)
873
ChildrenCreated occurs when the child controls (the input area, popup buttons, and embedded calendar or time view controls) are created. The example below shows how to add a link right next to the calendar popup button of a RadDatePicker. When the button is clicked the picker's clear() client method is called.
[VB] Handling the ChildrenCreated Event Protected Sub RadDatePicker1_ChildrenCreated(ByVal sender As Object, ByVal e As EventArgs) Dim picker As RadDatePicker = DirectCast(sender, RadDatePicker) Dim clearLink As New HyperLink() clearLink.NavigateUrl = String.Format("javascript:$find('{0}').clear()", picker.ClientID) clearLink.Text = "Clear" clearLink.ToolTip = "Clear the date picker" picker.Controls.Add(clearLink) End Sub [C#] Handling the ChildrenCreated Event protected void RadDatePicker1_ChildrenCreated(object sender, EventArgs e) { RadDatePicker picker = (RadDatePicker)sender; HyperLink clearLink = new HyperLink(); clearLink.NavigateUrl = string.Format("javascript:$find('{0}').clear()", picker.ClientID); clearLink.Text = "Clear"; clearLink.ToolTip = "Clear the date picker"; picker.Controls.Add(clearLink); }
DayRender occurs immediately before the calendar renders the cell for a single day in the day matrix. HeaderCellRender occurs immediately before the calendar renders a cell in the column or row headers (or the view selector). The HeaderCellRenderEventArgs passed in as a parameter has two properties, Cell and HeaderType. You can use the Cell property to configure the appearance of the cell and the HeaderType to determine where a given cell will be placed. This next example sets the Cell BackColor based on the HeaderType. Note that the "View" HeaderType denotes the View Selector button in the upper left hand corner of the calendar. Also be aware that you should set EnableViewSelector to true for this example.
874
[VB] Handling the HeaderCellRender Event Protected Sub RadCalendar1_HeaderCellRender(ByVal sender As Object, ByVal e As Telerik.Web.UI.Calendar.HeaderCellRenderEventArgs) Select Case e.HeaderType Case Telerik.Web.UI.Calendar.HeaderType.Column e.Cell.BackColor = System.Drawing.Color.AliceBlue Exit Select Case Telerik.Web.UI.Calendar.HeaderType.Row e.Cell.BackColor = System.Drawing.Color.PaleGreen Exit Select Case Telerik.Web.UI.Calendar.HeaderType.View e.Cell.BackColor = System.Drawing.Color.PaleTurquoise Exit Select End Select End Sub [C#] Handling the HeaderCellRender Event protected void RadCalendar1_HeaderCellRender(object sender, Telerik.Web.UI.Calendar.HeaderCellRenderEventArgs e) { switch (e.HeaderType) { case Telerik.Web.UI.Calendar.HeaderType.Column: e.Cell.BackColor = System.Drawing.Color.AliceBlue; break; case Telerik.Web.UI.Calendar.HeaderType.Row: e.Cell.BackColor = System.Drawing.Color.PaleGreen; break; case Telerik.Web.UI.Calendar.HeaderType.View: e.Cell.BackColor = System.Drawing.Color.PaleTurquoise; break; } }
SelectionChanged occurs when the user changes the current selection in the calendar. This event does not fire unless the AutoPostBack property is True. This event passes a SelectedDatesEventArgs that has a single property SelectedDates. SelectedDates is a DateTimeCollection. DefaultViewChanged occurs when the user changes the current view using the navigation controls in the title bar. This event does not fire unless the AutoPostBack property is True. This event passesDefaultViewChangedEventArgs as a parameter. This object has two properties, OldView and NewView. Both are CalendarView objects that contain extensive properties describing the view before and
875
876
877
878
1. Set the RadTabStrip CausesValidation property to false. 2. Just after the dpDepart date picker add a ASP.NETRequiredFieldValidator with the following properties:
ErrorMessage: "Departure date required" ControlToValidate: "dpDepart" ValidationGroup: "FlightsGroup" Text: "*"
879
ErrorMessage: "Arrival date required" ControlToValidate: "dpArrive" ValidationGroup: "FlightsGroup" Text: "*"
ErrorMessage: "The arrival date must be after the departure date" ControlToValidate: "dpArrive" ControlToCompare: "dpDepart" ValidationGroup: "FlightsGroup" Text: "*" Operator: "GreaterThan" Type: "Date"
5. Set the btnFlights ValidationGroup property to "FlightsGroup". Now when you click btnFlights the validation will fire for both date inputs. 6. Just after the dtpPickup date picker add a ASP.NETRequiredFieldValidator with the following properties:
ErrorMessage: "Pick-up date required" ControlToValidate: "dtpPickup" ValidationGroup: "CarsGroup" Text: "*"
7. Just after the dtpDropoff date picker add a ASP.NETRequiredFieldValidator with the following properties:
ErrorMessage: "Drop-off date required" ControlToValidate: "dtpDropoff" ValidationGroup: "CarsGroup" Text: "*"
8. Add a CustomValidator:
ClientValidationFunction: "CompareCarsDates" ErrorMessage: "Pick-up must be less than drop-off dateand time". ValidationGroup: "CarsGroup"
9. Set the btnCars ValidationGroup property to "CarsGroup". 10. Inside the <form> tag add the JavaScript below. The JavaScript method must match the ClientValidationFunction property value in the CustomValidator.The method takes a sender and event args. The"args" parametercontains an IsValid property that is set depending on the functions custom criteria. In this case the criteria is that the pick-up is less than the drop-off date and time. F[JavaScript] CustomValidator Compare Function <script type="text/javascript"> function CompareCarsDates(sender, args) { var dtpPickup = $find("<%= dtpPickup.ClientID %>");
880
To get the DOM element for any of the picker controls and the RadCalendar use the get_element() method. You can drill down to the DOM elements for the major parts that make upthe picker controls. To get the calendar or time popup buttons, use get_popupButton() or get_timePopupButton(). To get DOM elements for the popups use get_popupContainer() and get_timePopupContainer(). To get the textbox portion of the picker control use the get_textBox() method. The example below displays the calendar or time view popup by clicking a button that in turn fires a PopupAbove() method. PopupAbove()gets a reference to the div DOM element for the calendar or time view and a reference to the textbox. The method thengets the position of the text box and calculates the offset where the popup will be displayed at. The popup is displayed using the showPopup() method of the picker. You can call showPopup() without parameters to display the popup just below the text box. If you have screen real estate issues you can pass the x and y pixel coordinates to showPopup(). Another option is to use Telerik.Web.RadDatePickerPopupDirectionenumeration as shownin the example below where the popup is displayed just above the text box.
881
[ASP.NET] Using Picker DOM Elements function popupAbove(showCalendar) { logTitle("PopupAbove() begin "); // get a client side reference to the date time picker var picker = $find("<%= RadDateTimePicker1.ClientID %>"); // get a reference to the input textbox within the picker var textBox = picker.get_textBox(); // get a reference to the div DOM element for the calendar // or time view. Get the position of the text box, the // dimensions for the poup, and display the popup // at Y coordinate at the position of the textbox subtracting // the height of the popup. if (showCalendar) { var popupElement = picker.get_popupContainer(); var dimensions = picker.getElementDimensions(popupElement); var position = picker.getElementPosition(textBox); picker.set_popupDirection(Telerik.Web.RadDatePickerPopupDirection.TopLeft); picker.showPopup(); } else { var popupElement = picker.get_timePopupContainer(); var dimensions = picker.getElementDimensions(popupElement); var position = picker.getElementPosition(textBox); picker.set_popupDirection(Telerik.Web.RadDatePickerPopupDirection.TopLeft); picker.showTimePopup(); } logTitle("PopupAbove() end "); log("x = " + position.x + ", y = " + position.y + ", dimensions.height = " + dimensions.height, 2); } //... <telerik:RadDateTimePicker ID="RadDateTimePicker1"
882
PopupOpening and PopupClosingprovide an opportunity to call args.set_cancel() to prevent the popup from displaying or closing. Get a reference to the time view or calendar client object using args.get_popupControl(). In the PopupOpening event you can use args.set_cancelCalendarSynchronization() to prevent the popup control from synchronizing its value to the value in the input area. DateSelected is called immediately after the value of the control's selection has changed. You have access to the old and new dates as both Date objects and strings using get_oldDate(), get_newDate(), get_oldValue() and get_newValue().
You can also get a reference to one of the child elements of the picker and attach events. For example, in the pageLoad event (available automatically whenever you have a ScriptManager on the page) you could get a reference to a picker's date input client object and attach a ValueChanging event: [JavaScript] Assigning Events to Child Elements function pageLoad(sender, args) { // get a reference to the date time picker's // internal date input control and assign the ValueChanging client event var RadDateTimePicker1 = $find("<%=RadDateTimePicker1.ClientID%>"); var input = RadDateTimePicker1.get_dateInput(); input.add_valueChanging(valueChanging); }
883
884
Calendar Events
There are three events that fire when a date is clicked and fire in this order, OnDateClick, OnDateSelecting and OnDateSelected. Both OnDateClick and OnDateSelecting can be cancelled using the the set_cancel() method.
885
OnDateClick occurs when the user clicks on a date in the calendar (regardless of whether the date can be selected). The arguments surface the set_cancel() just mentioned, but also a get_domEvent() method that provides access to a lot of mouse information like the clientX and clientY coordinates:
OnDateClick arguments also include the get_renderDay() method returns the client that represent the clicked day. Here's an example that pops up a confirmation dialog when the date is clicked. Notice the DateTimeFormatInfo object being used here to format the date into it's readable form:
886
[JavaScript] Handling the DateClick Event function dateClick(sender, args) { logEvent("DateClick", args); var day = args.get_renderDay(); if (day.get_isSelectable()) { var date = day.get_date(); var dfi = sender.DateTimeFormatInfo; var formattedDate = dfi.FormatDate(day.get_date(), dfi.ShortDatePattern); var confirmClick = confirm("Are you sure you want to " + (day.get_isSelected() ? "unselect " : "select ") + formattedDate + "?"); args.set_cancel(!confirmClick); } }
OnDateSelecting fires immediately before the selected dates collection is updated to reflect the selection or de-selection of a date. This event has arguments that include set_cancel(), get_renderDay() and one new method get_isSelecting() which is true if the day is in the process of being selected and false if the day is being de-selected. OnDateSelected fires immediately after the value of the control's selection has been changed. The arguments for this event only surface get_renderDay().
There are a few calendar methods that respond to selector, row and column clicks: OnViewSelectorClick, OnRowHeaderClick and OnColumnHeaderClick. All three events can be canceled with the args.set_Cancel(). All three events also surface the get_domElement(). OnRowHeaderClick and OnColumnHeaderClick have an additional method, get_index() that returns the 1-based index of the row or column clicked. This next example shows an OnRowHeaderClick event handler implementation that displays a confirmation dialog:
887
[JavaScript] Handling the OnRowHeaderClick Event function rowHeaderClick(sender, args) { var msg = "Do you want to change the selection for row " + args.get_index(); var title = args.get_domElement().title; if (title != "") msg = msg + " (" + title + ")"; msg = msg + "?"; args.set_cancel(!confirm(msg)); } You can find the complete source for this project at: \VS Projects\DateTimeSchedule\Calendar_ClientSide
888
5. In the "Choose a Data Source Type" page of the wizard, select the Database icon. Click the OK button to continue.
889
This step will display the Configure Data Source dialog. 6. In the "Choose Your Data Connection" page of thewizard, click the New Connection... button. This step will display the "Add Connection" dialog 7. In the Add Connection dialog, click the Data Source Change... button. This step will display the Change Data Source dialog. 8. In the Change Data Source dialog, select the "Microsoft SQL Server Database File" data source option and click OK to close the dialog. This step will return you to the Add Connection dialog. 9. Configure the connection:
Click the Browse... button next to the "Database file name" entry. Navigate to the RadControls installation directory and select "SchedulerData.mdb" from the \Live Demos\App_Data directory. In a typical installation the path will be \Program Files\Telerik\RadControls for ASPNET AJAX<version>\Live Demos\App_Data. This step should return you to the Add Connection
890
You can click the Test Connection button to verify that your connection string will be good. Click OK to close the Add Connection dialog.
10. Back in the Configure Data Source dialog you should see the Telerik.mdfconnection. The dialog should look something like the screenshot below. Click the Next button to continue.
891
11. In the "Save the Connection String to the Application Configuration File" page of the wizard, click the Next button to continue. 12. In the "Configure the Select Statement" page of the wizard:
The "Appointments" table should already be selected (if its not, please do so now). Click the checkbox to select all columns of the Appointments table. Click the Advanced button, select the "Generate INSERT, UPDATE and DELETE" statements checkbox and click OK. Gotcha! If you forget this last step where the CRUD (create-read-update-delete) statements are created, the SqlDataSource will not have SQL to handle any of the database operations other than simple selection. You would still see the data displayed, you could still double-click a day cell in the scheduler to insert a new appointment, but nothing would be saved.
892
13. Click the Test Query button and check out the data we will be hooking up to the scheduler.
893
14. Click the Finish button to close the wizard. This last step brings you back to the Data Source Configuration Wizard. 15. In the Data Source Configuration Wizard, use the drop down lists to match updata fields to the columns in the Appointments table. The key field should be set to the "ID" column. The remaining columns should be set to:
Start End Subject Description (optional) Reminder (optional) RecurrenceRule (optional) RecurrenceParentID (optional)
894
16. Click the OK button to close the Data Source Configuration Wizard. 17. Check the Properties Window for the scheduler. Notice the Data category properties that have been populated by the wizard.
895
18. That's all there is to hooking up the basic properties of RadScheduler. We will take an extra step to position the scheduler to some data we know is already in the table. Set the SelectedDate property to "3/1/2007" and the SelectedView property to MonthView. 19. Press Ctl-F5 to run the application. 20. Experiment with the scheduler usability:
Double-click a day cell to add a new appointment. Go to "Options" and then add the appointment.
896
897
898
Notice that you can drag existing appointments to any visible day.
You can find the complete source for this project at: \VS Projects\DateTimeSchedule\GettingStarted_Scheduler
38.10Scheduler Resources
Multiple arbitrary resources can be assigned to any appointment. For example, resources might be people, rooms, equipment or any random items you want to associate with an appointment. To make this work you need an ID for the resource in the appointment table (e.g. "UserID")and a separate master table with columns for an ID and a text value to describe the resource. In this database diagram you can see the Appointments table from the Telerik.mdf demo file.
899
We can extend the scheduler "getting started" example by adding the users and rooms resources. 1. Add a SqlDataSource to the default page. Configure the data source to use the Users table:
Set the ID to "dsUsers". Use the Smart Tag to configure the data source. In the Configure Data Source Wizard, re-use the SchedulerDataConnectionString. Select both columns. Test the query if you like and finish the wizard.
2. Add another SqlDataSource to the default page. Configure the data source to use the Rooms table:
Set the ID to "dsRooms". In the Configure Data Source Wizard, re-use the SchedulerDataConnectionString. Select both columns. Test the query if you like and finish the wizard.
3. Using the RadScheduler Smart Tag, click the Resource Types ellipses.
900
4. Click the Add button to create a new resource. Set the properties:
Name: "Users" DataSourceID: "dsUsers" ForeignKeyField: "UserID" KeyField: "ID" TextField: "UserName"
5. Click the Add button to create a second resource. Set the properties:
Name: "Rooms" DataSourceID: "dsRooms" ForeignKeyField: "RoomID" KeyField: "ID" TextField: "RoomName"
901
6. Press Ctl-F5 to run the application. Try creating a new appointment and clicking the "more" link or doubleclick an existing appointment. The "More details" section of the update dialog now displays drop down lists for each resource.
You can find the complete source for this project at: \VS Projects\DateTimeSchedule\Scheduler_Resources
902
38.11Custom Attributes
You can attach custom data from one or more columns in your appointment table. To do this add to the column names to the CustomAttributeNames collection property. Also set the EnableCustomAttributeEditing property to true. TheAppointments table in the SchedulerData.mdb demonstration data file contains a "Annotation" column.The custom attributes get added to the "More details" section ofedit and insert forms as shown in the screenshot below.
1. Start with the Scheduler_Resources project. 2. In the Properties Window for the scheduler, click the CustomAttributeNames property ellipses. Add the attribute "Annotations" to the string collection editor and click OK. 3. Set the EnableCustomAttributeEditing property to "true". 4. Press Ctl-F5 to run the application.Insert an appointment an click the "more" link or edit an existing appointment. Notice that the custom attribute "Annotation" in the "Details" portion of the edit form. Verify that you can save and re-display the value.
Smart Tag
903
Properties
Position the initial date shown in the scheduler by setting the SelectedDate property. Likewise you can set the scheduler view, that is, have the scheduler display the day, week, month or a timeline viewusing the SelectedView property. You can also set the visible range of days and times using the properties FirstDayOfWeek, LastDayOfWeek, DayStartTime, DayEndTime, WorkDayStartTime and WorkDayEndTime. Control how the scheduler fits into the page real-estate by setting the OverFlowBehavior property to Expand or Scroll (default). Toggle visibility for major user interface elements using ShowAllDayRow, ShowDateHeaders, ShowFooter, ShowFullTime, ShowHeader, ShowHoursColumn, ShowMonthlyColumnHeader, ShowNavigationPane, ShowResourceHeaders, ShowViewTabs, and ShowWeeklyColumnHeader. By default you can add, edit and delete appointments but you can turn this ability off using the AllowInsert, AllowEdit and AllowDelete properties.
Data
As we saw earlier in the "Getting Started" section of this chapter, the Data properties let you define the data source and map all the appointment table columns to scheduler-specific data properties.
904
We have used all of these properties so far except the ProviderName. By default ProviderName is "Integrated", but you can use one of the providers supplied in the Telerik.Web.UI assembly, or you can implement your own. See the online help for examples of creating custom providers (http://www.telerik.com/help/aspnetajax/schedule_databindingusingadataprovider.html)and a reference implementation of an exchange provider (http://www.telerik.com/help/aspnet-ajax/data-binding-exchange-provider.html) to handle Outlook integration. To bind RadScheduler to a provider, set its Provider or ProviderName property. Use the ProviderName property when binding declaratively in the designer, and the Provider property when binding to a provider instance at runtime. Because providers supply information about appointments using the Telerik.Web.UI.Appointment type, you do not need to set the scheduler's DataKeyField, DataSubjectField, DataStartField, DataEndField, DataRecurrenceField, DataRecurrenceParentKeyField or ResourceTypes properties. If you need to assign multiple resources of the same type to an appointment you must use a provider.
Layout
You will find "View" properties in the Layout group of properties. Each view has common sub-properties.
905
Set the GroupByproperty to the name of aresource typeand GroupingDirection to either Horizontal or Vertical. This screenshot shows the TimelineView GroupBy set to "Rooms" and the GroupingDirection as Horizontal.
ShowResourceHeaders can be disabled to hide the column titling "Meeting room 101", "Meeting room 201" but typically you would want to leave this at the default of "true". UserSelectable toggles the visibility of each view in the view selector located at the upper right of the scheduler. There are also view-specific sub-properties that handle start and end times, the number of units of whatever time is being shown (days, hours, etc), heading formats and thattogglevisibility of specific UI elements for each view.
906
907
908
You can find the complete source for this project at: \VS Projects\DateTimeScheduler\Scheduler_Appointments
Recurrence Rules
When a user elects to make an appointment recurring, a record is set up in the database with a string representation of the recurrence data. The screenshot of the data below shows two records. The first is the master data for the recurring appointment. When the user first creates a recurring appointment, this is the record that is created. You can see the string representation of the recurrence incluing the start and end dates and the rule that defines when the appointment should recur. When the user decides to edit a single instance of the recurrence, an exception record is created with the RecurrenceRule set to NULL and the RecurrenceParentID pointing to the ID of the master record.
The RecurrenceRule also has two methods, ToString() to convert the rule to readable text as it will be stored in a database and TryParse() that reconstitutes the string back to a RecurrenceRule object.
909
910
911
912
913
Responding to TimeSlotEvents
Each time a time slot is created you get an opportunity to change the TimeSlot CssClass to style the slot. At the time of this writing, abilities are being added to this event to allow access to the controls within the time slot as well. [VB] Handling the TimeSlotCreated Event Protected Sub RadScheduler1_TimeSlotCreated(ByVal sender As Object, ByVal e As TimeSlotCreatedEventArgs) Log("TimeSlotCreated") If e.TimeSlot.Appointments.Count = 0 Then e.TimeSlot.CssClass = "OpenTimeSlots" End If End Sub [C#] Handling the TimeSlotCreated Event protected void RadScheduler1_TimeSlotCreated(object sender, TimeSlotCreatedEventArgs e) { Log("TimeSlotCreated"); if (e.TimeSlot.Appointments.Count == 0) { e.TimeSlot.CssClass = "OpenTimeSlots"; } }
914
Custom Commands
If you want to add a button within a template that should fire some custom action, handle the AppointmentCommand. Just set the CommandName property of a button to the string you will look for in the AppointmentCommand arguments CommandName property. The screenshot below shows an ImageButton with an "Outlook" icon (you can find Outlook.gif in the \VS Projects\Images directory). The ImageButton CommandName property is set to "Export".
The example below exports an Outlook calendar file. The RadScheduler ExportToICalendar() method takes an Appointment object and returns a string. [VB] Handling the AppointmentCommand Protected Sub RadScheduler1_AppointmentCommand(ByVal sender As Object, ByVal e As Telerik.Web.UI.AppointmentCommandEventArgs) If e.CommandName.Equals("Export") Then WriteCalendar(RadScheduler.ExportToICalendar(e.Container.Appointment)) End If End Sub [C#] Handling the AppointmentCommand protected void RadScheduler1_AppointmentCommand(object sender, Telerik.Web.UI.AppointmentCommandEventArgs e) { if (e.CommandName.Equals("Export")) { WriteCalendar(RadScheduler.ExportToICalendar(e.Container.Appointment)); } } The private WriteCalendar() method takes the appointment string and writes it out to the Response stream. [VB] Writing the Appointment String to the Response Private Sub WriteCalendar(ByVal data As String) Dim response As HttpResponse = Page.Response response.Clear() response.Buffer = True
915
916
917
You can also trigger the default Insert/Edit/Delete scheduler operations, much in the same way as if the user had initiated the action. For example, you could hook up to OnClientAppointmentContextMenu client event to grab the right-clicked appointment and display a context menu that will allow the user to edit or delete an appointment.
918
The RadContextMenu OnClientItemClicked event handler uses the saved appointment reference and calls the scheduler editAppointment() or deleteAppointment() methods.Both methods take a reference to the appointment as a parameter. [JavaScript] Editing and Deleting Appointments // holds the appointment reference var selectedAppointment = null; // Scheduler event responds to right-click of existing // appointment. This event handler saves off the // appointment that was right clicked as "selectedAppointment". // selectedAppointment is used later in the context menu // ClientItemClicked event handler. function ClientAppointmentContextMenu(sender, args) { selectedAppointment = args.get_appointment(); var menu = $find("<%= RadContextMenu1.ClientID %>"); menu.show(args.get_domEvent()); } function ClientItemClicked(sender, args) { var scheduler = $find("<%= RadScheduler1.ClientID %>"); var item = args.get_item(); switch (item.get_value()) { // display the advanced update form for editing case "edit": { scheduler.editAppointment(selectedAppointment); break; }
919
920
The setAllowSettings() method in the example below does most of the work and is called whena checkbox is clicked or when the page first loads.The CheckBoxList check boxes are extracted by way of the getElementsByTagName("input") call. You can then index into the array of elements and use the "checked" property in your calls to set_allowInsert(), set_allowEdit() and set_allowDelete(). Also notice that you can suppress the delete confirmation using the set_displayDeleteConfirmation() method. The last part of the setAllowSettings() method shows another client-side technique of controlling how the RadScheduler events are handled. Here the OnClientTimeSlotClick event is removed or added based on a checkbox value. Like the other RadControls, RadScheduler comes with a set of method pairs that add and remove event handlers. Also remember that multiple event handlers can be added to a single event. [JavaScript] Setting the Allow Insert/Edit/Delete Properties /* CheckBoxList Events */ function CheckItem(sender) { setAllowSettings(sender); } /* general MS AJAX Library Events */ function pageLoad() { setAllowSettings($get("<%= cbScheduler.ClientID %>")); } // toggles scheduler functionality based on checkbox selections function setAllowSettings(checkBoxList) { var checkBoxes = checkBoxList.getElementsByTagName("input"); var scheduler = $find("<%= RadScheduler1.ClientID %>"); // toggle the add/edit/delete built-in functionality scheduler.set_allowInsert(checkBoxes[0].checked);
921
922
Within the AppointmentTemplate tag you can add HTML markup and binding expressions. In the example below we add in an image tag that points to "Calendar.gif" in the project (you can find this gif file in the \VS Projects\Images directory). Then the <%# %> binding expression using Eval can be used to display any of the data fields bound to the scheduler like "Subject", "Start", "End" or even custom attributes you have defined in the Appointments table. [ASP.NET] Adding the AppointmentTemplate <telerik:RadScheduler ID="RadScheduler1" runat="server" DataEndField="End" DataKeyField="ID" DataRecurrenceField="RecurrenceRule" DataRecurrenceParentKeyField="RecurrenceParentID" DataSourceID="SqlDataSource1" DataStartField="Start" DataSubjectField="Subject" Skin="Sunset" CustomAttributeNames="Annotations" EnableCustomAttributeEditing="True"> <AppointmentTemplate> <img src="Calendar.gif" alt="Calendar" /> <span style="font-weight: bold; font-size: small"> <%# Eval("Subject") %></span> <br /> <b>Starts on: </b><%# Eval("Start")%> <b>Ends on: </b><%# Eval("End") %> <b>Notes: </b><i><%# Eval("Annotations") %></i> </AppointmentTemplate> </telerik:RadScheduler> The result when youbring up the scheduler shows the icon, the subject in a slightly larger font, the formatted start and end times, and the custom attribute "Annotations" field is output as "Notes".
923
If we take this a step farther and add another template, the InlineInsertTemplate to completely customize adding a new appointment. Here we use the Bind() method to get the two way data binding to work. [ASP.NET] Adding the InlineInsertTemplate <InlineInsertTemplate> <%--Calendar image--%> <img src="Images/Calendar.gif" alt="Calendar" /> <%--Subject--%> <telerik:RadTextBox ID="RadTextBox1" runat="server" Skin="Sunset" Text='<%# Bind("Subject") %>'> </telerik:RadTextBox> <br /> <%--Start and End times--%> <b>Starts on:  <telerik:RadDateTimePicker ID="RadDateTimePicker1" Skin="Sunset" runat="server" SelectedDate='<%# Bind("Start")%>'> </telerik:RadDateTimePicker> <b>Ends on:  <telerik:RadDateTimePicker ID="RadDateTimePicker2" Skin="Sunset" runat="server" SelectedDate='<%# Bind("End")%>'> </telerik:RadDateTimePicker> <%--Custom attributes "Annotations", i.e. "Notes" --%> <telerik:RadTextBox ID="RadTextBox2" runat="server"
924
38.17Summary
In this chapter we explored the features of the date and time picker, calendar and scheduler controls. You created some simple applications to become familiar with the controls. We explored the design time interfaces of each of the controls. We worked with the server-side API to explore the major objects that make up each
925
926
39.1 Objectives
Build the ExamScheduler user control. Configure the RadTreeView and RadScheduler for drag and drop. Learn how to handle the scheduler events to create new appointments as tree nodes are dropped on the scheduler and "reserve" existing appointments when a button in the appointment template is clicked. Also learn to format appointments as they are created based on the logged in user role and attribute data of the appointment. Integrate the ExamScheduler to both the user and admin ScheduleExams.ascx controls.
A "User" role login displays the scheduler only, and displays a calendar button and text so that the user can click to reserve an available appointment. Once the appointment is reserved, the user id and exam are recorded with the appointment and the appointment can no longer be deleted or reserved by any one else.
927
1. In the \ActiveSkillUI\Controls directory add a new Web User Control item and name it "ExamScheduler.ascx". 2. In the markup for the user control, add a SqlDataSource. This data source will supply aRadTreeView with a list of available exams. [ASP.NET] Defining the Exams Data Source <asp:SqlDataSource ID="dsExams" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="SELECT [ID], [Title] FROM [Exam]"> </asp:SqlDataSource> 3. Add a second SqlDataSource for the scheduler: [ASP.NET] Defining the Scheduler Data Source <asp:SqlDataSource ID="dsScheduler" runat="server" ConnectionString="<%$ ConnectionStrings:ActiveSkillConnectionString %>" SelectCommand="SELECT [ID], [ExamID], [UserID], [Subject], [StartTime], [EndTime], [Recurrence], [RecurParentID] FROM [Appointment_Data]" DeleteCommand="DELETE FROM [Appointment_Data] WHERE [ID] = @ID" InsertCommand="INSERT INTO [Appointment_Data] ([ExamID], [UserID], [Subject], [StartTime], [EndTime], [Recurrence], [RecurParentID]) VALUES (@ExamID, @UserID, @Subject, @StartTime, @EndTime, @Recurrence, @RecurParentID)" UpdateCommand="UPDATE [Appointment_Data] SET [ExamID] = @ExamID, [UserID] = @UserID, [Subject] = @Subject, [StartTime] = @StartTime, [EndTime] = @EndTime, [Recurrence] = @Recurrence, [RecurParentID] = @RecurParentID WHERE [ID] = @ID"> <DeleteParameters> <asp:Parameter Name="ID" Type="Int32" /> </DeleteParameters> <UpdateParameters> <asp:Parameter Name="ExamID" Type="Int32" /> <asp:Parameter Name="UserID" /> <asp:Parameter Name="Subject" Type="String" /> <asp:Parameter Name="StartTime" Type="DateTime" /> <asp:Parameter Name="EndTime" Type="DateTime" />
928
AllowInsert and AllowEdit are set to false. We only want to allow adding appointments through dragging or deleting by clicking the delete button in the appointment. ShowViewTabs is set to False. We just want to drag appointments to the default day view only. EnableAdvancedForm and StartEditingAdvancedForm are set to false. We only want to see the inline form. In the AppointmentTemplate there are two divs that will be toggled so that one will be visible for reserved appointments and the other invisible. Also in the AppointmentTemplate is a LinkButton control with the CommandName set to "Reserve". We will re-visit the Reserve command later when we add the server-side code.
929
930
2. In the Page_Load event add this assignment by [VB] Setting the Tree View Visibility Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Me.RadTreeView1.Visible = Roles.IsUserInRole("Admin") End Sub [C#] Setting the Tree View Visibility
931
932
933
934
39.6 Summary
In this chapter you implemented the ExamScheduler.ascx control. You configured a RadTreeView and RadScheduler for drag and drop. You learned how to handle scheduler events to create new appointments and modify the attributes of existing appointments based on commands set within the appointment template. You also learned how to format appointments as they are created based on the logged in user role and appointment attribute data. Finally, you integrated the ExamScheduler for use within ScheduleExams.ascx controls located within the \user and \admin directories.
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957