using System; using System.Data; using System.Drawing; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.Web; using System.Web.UI; using System.Web.UI.MobileControls; using System.Web.UI.MobileControls.Adapters; using ASPNetPortal.MobileControls; [ assembly:TagPrefix("ASPNetPortal.MobileControls", "portal") ] namespace ASPNetPortal { //********************************************************************* // // MobilePortalModuleControl // // The MobilePortalModuleControl class is the base class used for // each module user control in the mobile portal. Since it implements // the IContentsPane interface, any control inheriting from this class // can be used as a module in a portal tab. // //********************************************************************* public class MobilePortalModuleControl : UserControl, IContentsPane { private ModuleSettings _moduleConfiguration; private Control _summaryControl; //********************************************************************* // // MobilePortalModuleControl.ModuleConfiguration Property // // Returns the configuration information for this module. // //********************************************************************* public ModuleSettings ModuleConfiguration { get { return _moduleConfiguration; } set { _moduleConfiguration = value; } } //********************************************************************* // // MobilePortalModuleControl.Tab Property // // Returns the parent portal tab. // //********************************************************************* public MobilePortalTab Tab { get { return Parent as MobilePortalTab; } } //********************************************************************* // // MobilePortalModuleControl.ModuleTitle Property // // Returns the name of this module. // //********************************************************************* [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public String ModuleTitle { get { return _moduleConfiguration.ModuleTitle; } } //********************************************************************* // // MobilePortalModuleControl.ModuleId Property // // Returns the unique ID of this module. // //********************************************************************* [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int ModuleId { get { return _moduleConfiguration.ModuleId; } } //********************************************************************* // // IContentsPane.Title Property // // Returns the name of the module, to be used as the pane title // when used inside a tab. // //********************************************************************* String IPanelPane.Title { get { return _moduleConfiguration.ModuleTitle; } } //********************************************************************* // // IContentsPane.OnSetSummaryMode Method // // OnSetSummaryMode is called on each child pane when the parent tab // changes from showing summaries to individual details or vice versa. // This method calls the UpdateVisibility utility method to // update the visibility of child controls. // REVIEW: Probably could be done using an event handler instead. // //********************************************************************* void IContentsPane.OnSetSummaryMode() { UpdateVisibility(); } //********************************************************************* // // MobilePortalModuleControl.OnInit Method // // OnInit is called when the control is created and added to the // control tree. OnInit looks for a child control that renders the // summary view of the module, and creates a default one (with a // simple LinkCommand control) if no summary is found. // //********************************************************************* protected override void OnInit(EventArgs e) { base.OnInit(e); // Look for a control that renders the summary. _summaryControl = FindControl("summary"); // There could be no summary control, or the summary control may be // an empty panel. If there's no summary UI, automatically generate one. if (_summaryControl == null || (_summaryControl is Panel && !_summaryControl.HasControls())) { // Create and initialize a new LinkCommand control Command command = new LinkCommand(); command.Text = this.ModuleTitle; // Set the command name to the details command, so that // event bubbling can recognize it as a command to go to // details view. command.CommandName = ContentsPanel.DetailsCommand; // Add it to the appropriate place. if (_summaryControl != null) { _summaryControl.Controls.Add(command); } else { Controls.Add(command); _summaryControl = command; } } } //********************************************************************* // // MobilePortalModuleControl.OnLoad Method // // OnLoad is called when the control is created and added to the // control tree, after OnInit. OnLoad calls the UpdateVisibility // utility method to update the visibility of child controls. // //********************************************************************* protected override void OnLoad(EventArgs e) { base.OnLoad(e); UpdateVisibility(); } //********************************************************************* // // MobilePortalModuleControl.UpdateVisibility Method // // UpdateVisibility updates the visibility of child controls // depending on the current setting. If the module is currently // being shown in summary mode, all children except the summary // control are hidden. If the module is currently being shown // in details mode, only the summary control is hidden. // //********************************************************************* private void UpdateVisibility() { bool summary = Tab != null && Tab.SummaryView; foreach (Control child in Controls) { child.Visible = !summary; } if (_summaryControl != null) { _summaryControl.Visible = summary; } } } //********************************************************************* // // MobilePortalTab Class // // The MobilePortalTab class is used for each tab of the mobile // portal. // //********************************************************************* public class MobilePortalTab : ContentsPanel { } } namespace ASPNetPortal.MobileControls { //********************************************************************* // // LinkCommand Class // // The LinkCommand class is used for a simple custom version of the // Command control. Although the class itself has no added or modified // functionality, it allows a new adapter to be specified. On // HTML devices, this control renders as a hyperlink rather than // a button. // //********************************************************************* public class LinkCommand : Command { } //********************************************************************* // // HtmlLinkCommandAdapter Class // // The HtmlLinkCommandAdapter class is used to render the LinkCommand // control on an HTML device. Unlike the Command control, which renders // as a button, the HtmlLinkCommandAdapter renders a LinkCommand as // a hyperlink. Only the Render method needs to be overriden. // //********************************************************************* public class HtmlLinkCommandAdapter : HtmlCommandAdapter { //********************************************************************* // // HtmlLinkCommandAdapter.Render Method // // The Render method performs rendering of the LinkCommand control. // //********************************************************************* public override void Render(HtmlMobileTextWriter writer) { // Render a postback event as an anchor. RenderPostBackEventAsAnchor(writer, null, Control.Text); // Write a break, if necessary. writer.WriteBreak(); } } //********************************************************************* // // Panels Package // // The Panels Package is a set of bonus mobile controls used for // the IBuySpy Mobile Portal. The package provides a new set of // control classes. All of these controls inherit from the // System.Web.UI.MobileControls.Panel class. // // MultiPanel // A base class capable of managing multiple child controls, // called "panes". Each child pane must implement the // IPanelPane interface. // ChildPanel // A base class for panels that can be used as child panes // of MultiPanel panels. MultiPanel itself inherits from // ChildPanel, so you can nest one MultiPanel as a child // pane of another. // TabbedPanel // A specialized type of MultiPanel that comes with // adapters for rendering the panel as a tab view where // appropriate. On other devices, adapters render the // TabbedPanel using a separate menu screen. // ContentsPanel // A specialized type of MultiPanel that can show either // a summary view, where all child panes are shown // simultaneously, or a details view that shows the // active pane. Each child pane must implement the // IContentsPane interface. // // Although these controls are fairly advanced compared to the // rest of the portal, full source code is provided. // //********************************************************************* //********************************************************************* // // IPanelPane interface // // The IPanelPane interface must be implemented by any control // that needs to be a child pane of a MultiPanel or derivative // control. The interface has the following members: // // Title property // Returns the title of the pane. // //********************************************************************* public interface IPanelPane { String Title { get; } } //********************************************************************* // // IContentsPane interface // // The IContentsPane interface must be implemented by any control // that needs to be a child pane of a ContentsPanel control. // The interface has the following members: // // Title property // Returns the title of the pane. // OnSetSummaryMode method // Called when the ContentsPane control switches // from summary view to item details view. // //********************************************************************* public interface IContentsPane : IPanelPane { void OnSetSummaryMode(); } //********************************************************************* // // ChildPanel Class // // The ChildPanel Class is a control that inherits from // System.Web.UI.MobileControls.Panel, and can be placed inside // a MultiPanel control. Even MultiPanel inherits from ChildPanel, // allowing nesting of MultiPanel controls. // //********************************************************************* public class ChildPanel : Panel, IPanelPane, INamingContainer { //********************************************************************* // // IPanelPane.Title Property // // Returns the title of the pane. // //********************************************************************* String IPanelPane.Title { get { return this.Title; } } //********************************************************************* // // ChildPanel.Title Property // // Returns the title of the pane. // //********************************************************************* public String Title { get { // Load the title from the ViewState property bag, // defaulting to an empty String. String s = (String)ViewState["Title"]; return s != null ? s : String.Empty; } set { // Save the title to the ViewState property bag. ViewState["Title"] = value; } } //********************************************************************* // // ChildPanel.PaginateChildren Property // // The PaginateChildren property controls whether the form // can paginate children of the panel individually. Overriden // to allow contents to be paginated. // //********************************************************************* protected override bool PaginateChildren { get { return true; } } } //********************************************************************* // // MultiPanel Class // // The MultiPanel Class is a control that inherits from // ChildPanel, and can manage one or more child controls or "panes". // //********************************************************************* public class MultiPanel : ChildPanel { // Collection of panes. private PanelPaneCollection _panes; //********************************************************************* // // MultiPanel.Panes Property // // Returns the collection of child panes. // //********************************************************************* public PanelPaneCollection Panes { get { // If not yet created, create the collection. if (_panes == null) { _panes = new PanelPaneCollection(this); } return _panes; } } //********************************************************************* // // MultiPanel.ActivePane Property // // Get or set the currently active child pane. // //********************************************************************* public IPanelPane ActivePane { get { // Get the index of the active pane, and use it to // look up the active pane. int index = ActivePaneIndex; return (index != -1) ? Panes[index] : null; } set { // Find the index of the given pane, and use it to // set the active pane index. int index = Panes.IndexOf(value); if (index == -1) { throw new Exception("Pane not in Panes collection"); } ActivePaneIndex = index; } } //********************************************************************* // // MultiPanel.ActivePaneIndex Property // // Get or set the index of the currently active child pane. // //********************************************************************* public int ActivePaneIndex { get { // Get the index from the ViewState property bag, defaulting // to the first pane if not found. Object o = ViewState["ActivePaneIndex"]; if (o != null) { return (int)o; } else { return (Panes.Count > 0) ? 0 : -1; } } set { // Make sure index is within range. if (value < 0 || value >= Panes.Count) { throw new Exception("Active pane index out of range"); } // Set the index in the ViewState property bag. ViewState["ActivePaneIndex"] = value; } } //********************************************************************* // // MultiPanel.AddParsedSubObject Method // // AddParsedSubObject is called by the framework when a child // control is being added to the control from the persistence format. // AddParsedSubObject below checks if the added control is a // child pane, and automatically adds it to the Panes collection. // //********************************************************************* protected override void AddParsedSubObject(Object obj) { IPanelPane pane = obj as IPanelPane; // Only allow panes as children. if (pane == null) { throw new Exception("A MultiPanel control can only contain panes."); } // Add the pane to the Panes collection. Panes.AddInternal(pane); base.AddParsedSubObject(obj); } //********************************************************************* // // MultiPanel.OnRender Method // // OnRender is called by the framework to render the control. // By default, OnRender of a MultiPanel only renders the active // child pane. Specialized versions of the control, such as // TabbedPanel and ContentsPanel, have different behavior. // //********************************************************************* protected override void OnRender(HtmlTextWriter writer) { ((Control)ActivePane).RenderControl(writer); } //********************************************************************* // // MultiPanel.PaginateRecursive Method // // PaginateRecursive is called by the framework to recursively // paginate children. For MultiPanel controls, PaginateRecursive // only paginates the active child pane. // //********************************************************************* public override void PaginateRecursive(ControlPager pager) { Control activePane = (Control)ActivePane; // Active pane may not be a mobile control (e.g. it may be // a user control). MobileControl mobileCtl = activePane as MobileControl; if (mobileCtl != null) { // Paginate the children. mobileCtl.PaginateRecursive(pager); // Set own first and last page from results of child // pagination. this.FirstPage = mobileCtl.FirstPage; this.LastPage = pager.PageCount; } else { // Call the DoPaginateChildren utility method to // paginate a non-mobile child. int firstAssignedPage = -1; DoPaginateChildren(pager, activePane, ref firstAssignedPage); // Set own first and last page from results of child // pagination. if (firstAssignedPage != -1) { this.FirstPage = firstAssignedPage; } else { this.FirstPage = pager.GetPage(100); } this.LastPage = pager.PageCount; } } //********************************************************************* // // MultiPanel.DoPaginateRecursive Static Method // // The DoPaginateRecursive method paginates non-mobile child // controls, looking for mobile controls inside them. // //********************************************************************* private static void DoPaginateChildren(ControlPager pager, Control ctl, ref int firstAssignedPage) { // Search all children of the control. if (ctl.HasControls()) { foreach (Control child in ctl.Controls) { if (child.Visible) { // Look for a visible mobile control. MobileControl mobileCtl = child as MobileControl; if (mobileCtl != null) { // Paginate the mobile control. mobileCtl.PaginateRecursive(pager); // If this is the first control being paginated, // set the first assigned page. if (firstAssignedPage == -1) { firstAssignedPage = mobileCtl.FirstPage; } } else if (child is UserControl) { // Continue paginating user controls, which may contain // their own mobile children. DoPaginateChildren(pager, child, ref firstAssignedPage); } } } } } } //********************************************************************* // // PanelPaneCollection Class // // The PanelPaneCollection Class is used to keep a collection of // child panes of a MultiPanel control. The class implements // ICollection, so it can be used as a general collection. // //********************************************************************* public class PanelPaneCollection : ICollection { // Private instance variables. private MultiPanel _parent; private ArrayList _items = new ArrayList(); // Can only be instantiated by MultiPanel. internal PanelPaneCollection(MultiPanel parent) { // Save off reference to parent control. _parent = parent; } //********************************************************************* // // PanelPaneCollection.Add Method // // Adds a pane to the collection. // //********************************************************************* public void Add(IPanelPane pane) { // Add the pane to the parent's child controls collection. _parent.Controls.Add((Control)pane); _items.Add(pane); } //********************************************************************* // // PanelPaneCollection.AddInternal Method // // Adds a pane to the collection, but does not add it to the parent's // controls. This is called by the parent control itself to add // panes. // //********************************************************************* internal void AddInternal(IPanelPane pane) { _items.Add(pane); } //********************************************************************* // // PanelPaneCollection.Remove Method // // Removes a pane from the collection. // //********************************************************************* public void Remove(IPanelPane pane) { // Remove the pane from the parent's child controls collection. _parent.Controls.Remove((Control)pane); _items.Remove(pane); } //********************************************************************* // // PanelPaneCollection.Clear Method // // Removes all panes from the collection. // //********************************************************************* public void Clear() { // Remove all child controls from the parent. foreach (Control pane in _items) { _parent.Controls.Remove(pane); } _items.Clear(); } //********************************************************************* // // PanelPaneCollection.this[] Property // // Returns a pane by index. // //********************************************************************* public IPanelPane this[int index] { get { return (IPanelPane)_items[index]; } } //********************************************************************* // // PanelPaneCollection.Count Property // // Returns the number of panes in the collection. // //********************************************************************* public int Count { get { return _items.Count; } } //********************************************************************* // // PanelPaneCollection.IndexOf Method // // Returns the index of a given pane. // //********************************************************************* public int IndexOf(IPanelPane pane) { return _items.IndexOf(pane); } //********************************************************************* // // PanelPaneCollection.IsReadOnly Property // // Returns whether the collection is read-only. // //********************************************************************* public bool IsReadOnly { get { return _items.IsReadOnly; } } //********************************************************************* // // PanelPaneCollection.IsSynchronized Property // // Returns whether the collection is synchronized. // //********************************************************************* public bool IsSynchronized { get { return false; } } //********************************************************************* // // PanelPaneCollection.SyncRoot Property // // Returns the collection's synchronization root. // //********************************************************************* public Object SyncRoot { get { return this; } } //********************************************************************* // // PanelPaneCollection.CopyTo Method // // Copies the contents of the collection to an array. // //********************************************************************* public void CopyTo(Array array, int index) { foreach (Object item in _items) { array.SetValue (item, index++); } } //********************************************************************* // // PanelPaneCollection.GetEnumerator Method // // Returns an object capable of enumerating the collection. // //********************************************************************* public virtual IEnumerator GetEnumerator() { return _items.GetEnumerator (); } } //********************************************************************* // // TabbedPanel Class // // The TabbedPanel Class is a control that inherits from MultiPanel, // and provides the ability for the user to switch between panels. // The TabbedPanel also has adapters defined for custom rendering. // //********************************************************************* public class TabbedPanel : MultiPanel, IPostBackEventHandler { //********************************************************************* // // TabbedPanel.OnRender Method // // OnRender is called by the framework to render the control. // The TabbedPanel's OnRender method overrides the behavior // of MultiPanel, and directly calls the adapter to do rendering. // //********************************************************************* protected override void OnRender(HtmlTextWriter writer) { Adapter.Render(writer); } //********************************************************************* // // TabbedPanel.TabColor Property // // Gets or sets the background color used for each tab label, when // tabbed rendering is used. // //********************************************************************* public Color TabColor { get { // Get the color from the ViewState property bag, defaulting // to an empty color. Object o = ViewState["TabColor"]; return o != null ? (Color)o : Color.Empty; } set { // Save the color in the ViewState property bag. ViewState["TabColor"] = value; } } //********************************************************************* // // TabbedPanel.TabTextColor Property // // Gets or sets the text color used for each tab label, when // tabbed rendering is used. // //********************************************************************* public Color TabTextColor { get { // Get the color from the ViewState property bag, defaulting // to an empty color. Object o = ViewState["TabTextColor"]; return o != null ? (Color)o : Color.Empty; } set { // Save the color in the ViewState property bag. ViewState["TabTextColor"] = value; } } //********************************************************************* // // TabbedPanel.ActiveTabColor Property // // Gets or sets the background color used for the active tab label, when // tabbed rendering is used. // //********************************************************************* public Color ActiveTabColor { get { // Get the color from the ViewState property bag, defaulting // to an empty color. Object o = ViewState["ActiveTabColor"]; return o != null ? (Color)o : Color.Empty; } set { // Save the color in the ViewState property bag. ViewState["ActiveTabColor"] = value; } } //********************************************************************* // // TabbedPanel.ActiveTabTextColor Property // // Gets or sets the text color used for the active tab label, when // tabbed rendering is used. // //********************************************************************* public Color ActiveTabTextColor { get { // Get the color from the ViewState property bag, defaulting // to an empty color. Object o = ViewState["ActiveTabTextColor"]; return o != null ? (Color)o : Color.Empty; } set { // Save the color in the ViewState property bag. ViewState["ActiveTabTextColor"] = value; } } //********************************************************************* // // TabbedPanel.TabsPerRow Property // // Gets or sets the number of tabs to be displayed per row, when // tabbed rendering is used. // //********************************************************************* public int TabsPerRow { get { // Get the value from the ViewState property bag, defaulting // to 4. Object o = ViewState["TabsPerRow"]; return o != null ? (int)o : 4; } set { // Save the value in the ViewState property bag. ViewState["TabsPerRow"] = value; } } //********************************************************************* // // IPostBackEventHandler.RaisePostBackEvent Property // // RaisePostBackEvent is called by the framework when the control // is to receive a postback event. Responds to the event by // using the event information to switch to another active pane. // //********************************************************************* public virtual void RaisePostBackEvent(String eventArgument) { EventArgs e = new EventArgs(); // Call Deactivate event handler. OnTabDeactivate(e); ActivePaneIndex = Int32.Parse(eventArgument); // Call Activate event handler. OnTabActivate(e); } // Public events. public event EventHandler TabActivate; public event EventHandler TabDeactivate; //********************************************************************* // // IPostBackEventHandler.OnTabActivate Method // // OnTabActivate is called when a child pane is newly activated // as a result of user interaction, and raises the TabActivate event. // //********************************************************************* protected virtual void OnTabActivate(EventArgs e) { if (TabActivate != null) { TabActivate(this, e); } } //********************************************************************* // // IPostBackEventHandler.OnTabDeactivate Method // // OnTabDeactivate is called when a child pane is deactivated // as a result of user interaction, and raises the TabDeactivate event. // //********************************************************************* protected virtual void OnTabDeactivate(EventArgs e) { if (TabDeactivate != null) { TabDeactivate(this, e); } } } //********************************************************************* // // ContentsPanel Class // // The ContentsPanel Class is a control that inherits from MultiPanel, // and can render child panes in one of two views. In Summary View, // the control renders each of its child panes (which, in turn, would // probably show only summarized views of themselves) In Details View // the control only renders the active pane. // //********************************************************************* public class ContentsPanel : MultiPanel { // Constants for command names that can be used for // event bubbling in custom UI. public static readonly String DetailsCommand = "details"; public static readonly String SummaryCommand = "summary"; //********************************************************************* // // ContentsPanel.SummaryView Property // // Get or set the view of the panel to either Summary (true) // or Details (false) view. // //********************************************************************* public bool SummaryView { get { // Get the setting from the ViewState property bag, defaulting // to true. Object o = ViewState["SummaryView"]; return (o != null) ? (bool)o : true; } set { // Save the setting in the ViewState property bag. ViewState["SummaryView"] = value; // Notify each child pane of the switched mode. foreach (IContentsPane pane in Panes) { pane.OnSetSummaryMode(); } } } //********************************************************************* // // ContentsPanel.Render Method // // Called by the framework to render the control. The behavior differs // depending on whether Summary or Details view is showing. // //********************************************************************* protected override void Render(HtmlTextWriter writer) { if (SummaryView) { // Render all panes in Summary view. RenderChildren(writer); } else { // Render only the active pane in Details view. ((Control)ActivePane).RenderControl(writer); } } //********************************************************************* // // ContentsPanel.OnBubbleEvent Method // // Called by the framework when postback events are bubbled up // from a child control. If the event source uses the special // command names listed above, this method automatically responds // to the event to change modes. This allows the developer to // provide UI for showing item details by simply placing a // control with the appropriate command name in a child pane. // //********************************************************************* protected override bool OnBubbleEvent(Object sender, EventArgs e) { bool handled = false; System.Web.UI.WebControls.CommandEventArgs commandArgs = e as System.Web.UI.WebControls.CommandEventArgs; if (commandArgs != null && commandArgs.CommandName != null) { String commandName = commandArgs.CommandName.ToLower(); // Look for recognized command names. if (commandName == DetailsCommand) { // To show details, first find the child pane in which the // event source is located. Control ctl = (Control)sender; while (ctl != null && ctl != this) { IPanelPane pane = ctl as IPanelPane; if (pane != null) { // Make the pane active, and switch into Details view. ActivePane = pane; SummaryView = false; handled = true; break; } ctl = ctl.Parent; } } else if (commandName == SummaryCommand) { // Switch into Summary view. SummaryView = true; handled = true; } } return handled; } //********************************************************************* // // ContentsPanel.ShowDetails Method // // The ShowDetails method switches the control into Details view, // and makes the specified child pane active. Child panes can // call this method to activate themselves. // //********************************************************************* public void ShowDetails(IPanelPane pane) { SummaryView = false; ActivePane = pane; } } //********************************************************************* // // HtmlTabbedPanelAdapter Class // // The HtmlTabbedPanelAdapter provides rendering for the TabbedPanel // class on devices that support HTML and JScript. // //********************************************************************* public class HtmlTabbedPanelAdapter : HtmlControlAdapter { //********************************************************************* // // HtmlTabbedPanelAdapter.Control Property // // Returns the attached control, strongly typed as a TabbedPanel. // //********************************************************************* protected new TabbedPanel Control { get { return (TabbedPanel)base.Control; } } //********************************************************************* // // HtmlTabbedPanelAdapter.Render Method // // Renders the control. The TabbedPanel is rendered as one or more // rows of tabs that the user can click on to move between tabs. // //********************************************************************* public override void Render(HtmlMobileTextWriter writer) { IPanelPane activePane = Control.ActivePane; int tabsPerRow = Control.TabsPerRow; PanelPaneCollection panes = Control.Panes; int paneCount = panes.Count; // Figure out the number of visible panes. int[] visiblePanes = new int[paneCount]; int visiblePaneCount = 0; for (int i = 0; i < paneCount; i++) { if (((Control)panes[i]).Visible) { visiblePanes[visiblePaneCount++] = i; } } // Calculate how many rows are necessary. int rows = (visiblePaneCount + tabsPerRow - 1) / tabsPerRow; // make sure tabsPerRow doesn't exceed the number of visible panes tabsPerRow = (Control.TabsPerRow > visiblePaneCount) ? visiblePaneCount : Control.TabsPerRow; // Open the table. writer.WriteBeginTag("table"); writer.WriteAttribute("cellspacing", "0"); writer.WriteAttribute("cellpadding", "2"); writer.WriteAttribute("border", "0"); writer.WriteLine(">"); for (int row = rows - 1; row >= 0; row--) { writer.WriteFullBeginTag("tr"); writer.WriteLine(); for (int col = 0; col < tabsPerRow; col++) { writer.WriteBeginTag("td"); writer.WriteAttribute("width", "0"); writer.Write(">"); writer.WriteEndTag("td"); int i = row * tabsPerRow + col; if (row > 0 && i >= visiblePaneCount) { writer.WriteFullBeginTag("td"); writer.WriteEndTag("td"); continue; } int index = visiblePanes[i]; IPanelPane child = panes[index]; if (child == activePane) { writer.WriteBeginTag("td"); writer.WriteAttribute("bgcolor", GetColorString(Control.ActiveTabColor, "#333333")); writer.Write(">"); writer.WriteBeginTag("font"); writer.WriteAttribute("face", "Verdana"); writer.WriteAttribute("size", "-2"); writer.WriteAttribute("color", GetColorString(Control.ActiveTabTextColor, "#000000")); writer.Write(">"); writer.WriteFullBeginTag("b"); writer.Write(" "); writer.WriteText(child.Title, true); writer.Write(" "); writer.WriteEndTag("b"); writer.WriteEndTag("font"); writer.WriteEndTag("td"); writer.WriteLine(); } else { writer.WriteBeginTag("td"); writer.WriteAttribute("bgcolor", GetColorString(Control.TabColor, "#cccccc")); writer.Write(">"); writer.WriteBeginTag("font"); writer.WriteAttribute("face", "Verdana"); writer.WriteAttribute("size", "-2"); writer.WriteAttribute("color", GetColorString(Control.TabTextColor, "#000000")); writer.Write(">"); writer.Write(" "); writer.WriteBeginTag("a"); RenderPostBackEventAsAttribute(writer, "href", index.ToString()); writer.Write(">"); writer.WriteText(child.Title, true); writer.WriteEndTag("a"); writer.Write(" "); writer.WriteEndTag("font"); writer.WriteEndTag("td"); writer.WriteLine(); } } writer.WriteEndTag("tr"); writer.WriteLine(); if (row > 0) { writer.WriteFullBeginTag("tr"); writer.WriteBeginTag("td"); writer.WriteAttribute("height", "1"); writer.Write(">"); writer.WriteEndTag("td"); writer.WriteEndTag("tr"); writer.WriteLine(); } } writer.WriteEndTag("table"); writer.WriteLine(); writer.WriteBeginTag("table"); writer.WriteAttribute("width", "100%"); writer.WriteAttribute("height", "2"); writer.WriteAttribute("border", "0"); writer.WriteAttribute("cellspacing", "0"); writer.WriteAttribute("bgcolor", "#000000"); writer.Write(">"); writer.WriteFullBeginTag("tr"); writer.WriteFullBeginTag("td"); writer.WriteEndTag("td"); writer.WriteEndTag("tr"); writer.WriteEndTag("table"); writer.WriteBreak(); ((Control)activePane).RenderControl(writer); } private static String GetColorString(Color color, String defaultColor) { return color != Color.Empty ? ColorTranslator.ToHtml(color) : defaultColor; } } public class WmlTabbedPanelAdapter : WmlControlAdapter { private List _menu; protected new TabbedPanel Control { get { return (TabbedPanel)base.Control; } } public override void OnInit(EventArgs e) { _menu = new List(); _menu.ItemCommand += new ListCommandEventHandler(OnListItemCommand); Control.Controls.AddAt(0, _menu); } public override void OnLoad(EventArgs e) { _menu.Items.Clear(); int index = 0; foreach (IPanelPane child in Control.Panes) { if (((Control)child).Visible) { _menu.Items.Add(new MobileListItem(child.Title, index.ToString())); } index++; } } public override void Render(WmlMobileTextWriter writer) { Style st = new Style(); st.Wrapping = (Wrapping)Style[Style.WrappingKey, true]; st.Alignment = (Alignment)Style[Style.AlignmentKey, true]; writer.EnterLayout(st); if (_menu.Visible) { _menu.RenderControl(writer); } else { ((Control)Control.ActivePane).RenderControl(writer); } writer.ExitLayout(st); } private void OnListItemCommand(Object sender, ListCommandEventArgs e) { _menu.Visible = false; Control.RaisePostBackEvent(e.ListItem.Value); } } public class ChtmlTabbedPanelAdapter : HtmlControlAdapter { protected new TabbedPanel Control { get { return (TabbedPanel)base.Control; } } public override void Render(HtmlMobileTextWriter writer) { writer.EnterStyle(Style); IPanelPane activePane = Control.ActivePane; writer.Write("[ "); int index = 0; foreach (IPanelPane child in Control.Controls) { if (!((Control)child).Visible) { index++; continue; } if (index > 0) { writer.Write(" | "); } if (child == activePane) { writer.Write(""); writer.WriteText(child.Title, true); writer.Write(""); } else { writer.WriteBeginTag("a"); RenderPostBackEventAsAttribute(writer, "href", index.ToString()); writer.Write(">"); writer.WriteText(child.Title, true); writer.WriteEndTag("a"); } index++; } writer.Write(" ]"); writer.WriteBreak(); ((Control)activePane).RenderControl(writer); writer.ExitStyle(Style); } } }