1 //------------------------------------------------------------------------------ 2 // <copyright file="Form.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 using System.Web.Mobile; 8 using System.Web.UI; 9 using System.Collections; 10 using System.ComponentModel; 11 using System.ComponentModel.Design; 12 using System.Globalization; 13 using System.Security.Permissions; 14 15 namespace System.Web.UI.MobileControls 16 { 17 /// <include file='doc\Form.uex' path='docs/doc[@for="Form"]/*' /> 18 [ 19 ControlBuilderAttribute(typeof(FormControlBuilder)), 20 DefaultEvent("Activate"), 21 Designer(typeof(System.Web.UI.Design.MobileControls.FormDesigner)), 22 DesignerAdapter(typeof(System.Web.UI.MobileControls.Adapters.HtmlFormAdapter)), 23 PersistChildren(true), 24 ToolboxData("<{0}:Form runat=\"server\"></{0}:Form>"), 25 ToolboxItem("System.Web.UI.Design.WebControlToolboxItem, " + AssemblyRef.SystemDesign) 26 ] 27 [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 28 [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] 29 [Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")] 30 public class Form : Panel, ITemplateable, IPostBackEventHandler 31 { 32 33 private static readonly Object EventActivate = new Object(); 34 private static readonly Object EventDeactivate = new Object(); 35 private static readonly Object EventPaginated = new Object(); 36 37 private PagerStyle _pagerStyle; 38 private int _cachedCurrentPage = -1; 39 private Panel _headerContainer = null; 40 private Panel _footerContainer = null; 41 private Panel _scriptContainer = null; 42 43 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Form"]/*' /> Form()44 public Form() 45 { 46 _pagerStyle = new PagerStyle(); 47 _pagerStyle.SetControl(this); 48 } 49 50 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Title"]/*' /> 51 /// <summary> 52 /// <para> 53 /// Gets or sets the title used to identify the form. 54 /// </para> 55 /// </summary> 56 /// <value> 57 /// <para> 58 /// The title may be rendered as part of the form, on devices 59 /// that support a title separate from page content (e.g., on 60 /// the title bar of a browser using the title tag in HTML). 61 /// </para> 62 /// </value> 63 [ 64 Bindable(true), 65 DefaultValue(""), 66 MobileCategory(SR.Category_Appearance), 67 MobileSysDescription(SR.Form_Title) 68 ] 69 public String Title 70 { 71 get 72 { 73 String s = (String) ViewState["Title"]; 74 return((s != null) ? s : String.Empty); 75 } 76 set 77 { 78 ViewState["Title"] = value; 79 } 80 } 81 82 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Method"]/*' /> 83 [ 84 Bindable(true), 85 DefaultValue(FormMethod.Post), 86 MobileCategory(SR.Category_Behavior), 87 MobileSysDescription(SR.Form_Method) 88 ] 89 public FormMethod Method 90 { 91 get 92 { 93 Object o = ViewState["Method"]; 94 return ((o != null) ? (FormMethod)o : FormMethod.Post); 95 } 96 set 97 { 98 ViewState["Method"] = value; 99 } 100 } 101 102 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Action"]/*' /> 103 [ 104 Bindable(true), 105 DefaultValue(""), 106 Editor(typeof(System.Web.UI.Design.UrlEditor), 107 typeof(System.Drawing.Design.UITypeEditor)), 108 MobileCategory(SR.Category_Behavior), 109 MobileSysDescription(SR.Form_Action) 110 ] 111 public String Action 112 { 113 get 114 { 115 String s = (String) ViewState["Action"]; 116 return((s != null) ? s : String.Empty); 117 } 118 set 119 { 120 ViewState["Action"] = value; 121 } 122 } 123 124 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PagerStyle"]/*' /> 125 [ 126 DefaultValue(null), 127 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 128 MobileCategory(SR.Category_Style), 129 MobileSysDescription(SR.Form_PagerStyle), 130 NotifyParentProperty(true) 131 ] 132 public PagerStyle PagerStyle 133 { 134 get 135 { 136 return _pagerStyle; 137 } 138 } 139 140 /// <internalonly/> RaisePostBackEvent(String eventArgument)141 protected void RaisePostBackEvent(String eventArgument) 142 { 143 // If the event argument is all numeric, then it's a pager event. 144 145 bool notANumber = false; 146 int length = eventArgument.Length; 147 for (int i = 0; i < length; i++) 148 { 149 char c = eventArgument[i]; 150 if (c < '0' || c > '9') 151 { 152 notANumber = true; 153 break; 154 } 155 } 156 157 if (!notANumber && length > 0) 158 { 159 try 160 { 161 int page = Int32.Parse(eventArgument, CultureInfo.InvariantCulture); 162 if (page > 0) 163 { 164 int oldPage = _currentPage; 165 if(_cachedCurrentPage == -1) 166 { 167 _currentPage = page; 168 _cachedCurrentPage = page; 169 } 170 171 // currentpage may != page if page is invalid 172 OnPageChange(oldPage, _currentPage); 173 } 174 return; 175 } 176 catch 177 { 178 // Argument may be invalid number, so let adapter handle it. 179 } 180 } 181 182 Adapter.HandlePostBackEvent(eventArgument); 183 } 184 185 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Activate"]/*' /> 186 [ 187 MobileCategory(SR.Category_Action), 188 MobileSysDescription(SR.Form_OnActivate) 189 ] 190 public event EventHandler Activate 191 { 192 add 193 { 194 Events.AddHandler(EventActivate, value); 195 } 196 remove 197 { 198 Events.RemoveHandler(EventActivate, value); 199 } 200 } 201 202 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Deactivate"]/*' /> 203 [ 204 MobileCategory(SR.Category_Action), 205 MobileSysDescription(SR.Form_OnDeactivate) 206 ] 207 public event EventHandler Deactivate 208 { 209 add 210 { 211 Events.AddHandler(EventDeactivate, value); 212 } 213 remove 214 { 215 Events.RemoveHandler(EventDeactivate, value); 216 } 217 } 218 219 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Paginated"]/*' /> 220 [ 221 MobileCategory(SR.Category_Action), 222 MobileSysDescription(SR.Form_OnPaginated) 223 ] 224 public event EventHandler Paginated 225 { 226 add 227 { 228 Events.AddHandler(EventPaginated, value); 229 } 230 remove 231 { 232 Events.RemoveHandler(EventPaginated, value); 233 } 234 } 235 236 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Header"]/*' /> 237 [ 238 Bindable(false), 239 Browsable(false), 240 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 241 ] 242 public Panel Header 243 { 244 get 245 { 246 return _headerContainer; 247 } 248 } 249 250 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Footer"]/*' /> 251 [ 252 Bindable(false), 253 Browsable(false), 254 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 255 ] 256 public Panel Footer 257 { 258 get 259 { 260 return _footerContainer; 261 } 262 } 263 264 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Script"]/*' /> 265 [ 266 Bindable(false), 267 Browsable(false), 268 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 269 ] 270 public Panel Script 271 { 272 get 273 { 274 return _scriptContainer; 275 } 276 } 277 278 internal bool Activated = false; 279 FireActivate(EventArgs e)280 internal void FireActivate(EventArgs e) 281 { 282 if (!Activated) 283 { 284 Activated = true; 285 OnActivate(e); 286 } 287 } 288 FireDeactivate(EventArgs e)289 internal void FireDeactivate(EventArgs e) 290 { 291 if (Activated) 292 { 293 Activated = false; 294 OnDeactivate(e); 295 } 296 } 297 298 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnActivate"]/*' /> OnActivate(EventArgs e)299 protected virtual void OnActivate(EventArgs e) 300 { 301 EventHandler onActivate = (EventHandler)Events[EventActivate]; 302 if (onActivate != null) 303 { 304 onActivate(this, e); 305 } 306 } 307 308 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnDeactivate"]/*' /> OnDeactivate(EventArgs e)309 protected virtual void OnDeactivate(EventArgs e) 310 { 311 EventHandler onDeactivate = (EventHandler)Events[EventDeactivate]; 312 if (onDeactivate != null) 313 { 314 onDeactivate(this, e); 315 } 316 } 317 318 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.HasActivateHandler"]/*' /> HasActivateHandler()319 public virtual bool HasActivateHandler() 320 { 321 return Events[EventActivate] != null; 322 } 323 324 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.HasDeactivateHandler"]/*' /> HasDeactivateHandler()325 public virtual bool HasDeactivateHandler() 326 { 327 return Events[EventDeactivate] != null; 328 } 329 330 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnPaginated"]/*' /> OnPaginated(EventArgs e)331 protected virtual void OnPaginated(EventArgs e) 332 { 333 EventHandler onPaginated = (EventHandler)Events[EventPaginated]; 334 if (onPaginated != null) 335 { 336 onPaginated(this, e); 337 } 338 } 339 340 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnInit"]/*' /> OnInit(EventArgs e)341 protected override void OnInit(EventArgs e) 342 { 343 if (MobilePage != null && !MobilePage.DesignMode) 344 { 345 // Be sure we're not included in any other Forms. 346 for (Control control = this.Parent; control != null; control = control.Parent) 347 { 348 Form parentForm = control as Form; 349 if (parentForm != null) 350 { 351 throw new Exception(SR.GetString(SR.Form_NestedForms, 352 this.ID, 353 parentForm.ID)); 354 } 355 } 356 } 357 358 base.OnInit(e); 359 } 360 361 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.GetLinkedForms"]/*' /> GetLinkedForms(int optimumPageWeight)362 public IList GetLinkedForms(int optimumPageWeight) 363 { 364 // Always add itself to the list as the first one 365 UniqueSet set = new UniqueSet(); 366 set.Add(this); 367 368 // If the form has a deactivate handler, then we 369 // can't send the form with linked forms, because server interaction 370 // is necessary to move between forms. 371 372 if (HasDeactivateHandler()) 373 { 374 return set; 375 } 376 377 // Will stop once no new forms are added in a pass, or has 378 // reached the optimum page weight. 379 380 int totalWeight = 0; 381 int i; 382 383 // negative means the caller doesn't care about the weight 384 bool checkWeight = optimumPageWeight >= 0; 385 386 for (i = 0; i < set.Count; i++) 387 { 388 Form form = (Form)set[i]; 389 390 if (checkWeight) 391 { 392 totalWeight += form.GetVisibleWeight(); 393 if (totalWeight > optimumPageWeight) 394 { 395 break; 396 } 397 } 398 form.AddLinkedForms(set); 399 } 400 401 // More forms may have been linked than the total weight allows. 402 // Remove these. 403 404 if (i != 0 && // i == 0 means only one form is in the list 405 i < set.Count) 406 { 407 for (int j = set.Count - 1; j >= i; j--) 408 { 409 set.RemoveAt(j); 410 } 411 } 412 413 return set; 414 } 415 416 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.CreateDefaultTemplatedUI"]/*' /> CreateDefaultTemplatedUI(bool doDataBind)417 public override void CreateDefaultTemplatedUI(bool doDataBind) 418 { 419 ITemplate headerTemplate = GetTemplate(Constants.HeaderTemplateTag); 420 ITemplate footerTemplate = GetTemplate(Constants.FooterTemplateTag); 421 ITemplate scriptTemplate = GetTemplate(Constants.ScriptTemplateTag); 422 423 if (scriptTemplate != null) 424 { 425 _scriptContainer = new TemplateContainer(); 426 // The scriptTemplate is not added to the controls tree, so no need to do 427 // CheckedInstantiateTemplate to check for infinite recursion. 428 scriptTemplate.InstantiateIn(_scriptContainer); 429 _scriptContainer.EnablePagination = false; 430 } 431 432 if (headerTemplate != null) 433 { 434 _headerContainer = new TemplateContainer(); 435 CheckedInstantiateTemplate (headerTemplate, _headerContainer, this); 436 _headerContainer.EnablePagination = false; 437 Controls.AddAt(0, _headerContainer); 438 } 439 440 if (footerTemplate != null) 441 { 442 _footerContainer = new TemplateContainer(); 443 CheckedInstantiateTemplate (footerTemplate, _footerContainer, this); 444 _footerContainer.EnablePagination = false; 445 Controls.Add(_footerContainer); 446 } 447 448 // Do not call base.CreateDefaultTemplatedUI(), since we don't want 449 // Forms to have ContentTemplates as Panels do. 450 } 451 452 private int _pageCount = -1; 453 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PageCount"]/*' /> 454 [ 455 Bindable(false), 456 Browsable(false), 457 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 458 ] 459 public int PageCount 460 { 461 get 462 { 463 // If not yet paginated, it's okay to return -1. 464 465 return _pageCount; 466 } 467 } 468 469 private int _currentPage = 1; 470 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.CurrentPage"]/*' /> 471 [ 472 Bindable(false), 473 Browsable(false), 474 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 475 ] 476 public int CurrentPage 477 { 478 get 479 { 480 return _currentPage; 481 } 482 set 483 { 484 if (_currentPage != value) 485 { 486 OnPageChange (_currentPage, value); 487 } 488 _currentPage = value; 489 _cachedCurrentPage = _currentPage; 490 } 491 } 492 493 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.BreakAfter"]/*' /> 494 [ 495 Bindable(false), 496 Browsable(false), 497 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 498 EditorBrowsable(EditorBrowsableState.Never) 499 ] 500 public override bool BreakAfter 501 { 502 get 503 { 504 if (MobilePage.DesignMode) 505 { 506 return true; 507 } 508 throw new Exception( 509 SR.GetString(SR.Form_PropertyNotAccessible, "BreakAfter")); 510 } 511 512 set 513 { 514 throw new Exception( 515 SR.GetString(SR.Form_PropertyNotSettable, "BreakAfter")); 516 } 517 } 518 519 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnPreRender"]/*' /> OnPreRender(EventArgs e)520 protected override void OnPreRender(EventArgs e) 521 { 522 // AUI 3630 523 base.OnPreRender(e); 524 525 _pageCount = PaginateForm(); 526 527 // Clamp to 1 < _currentPage <= PageCount 528 529 int page = Math.Max(Math.Min(_currentPage, _pageCount), 1); 530 if(_currentPage != page) 531 { 532 _currentPage = page; 533 } 534 535 if ((Paginate) || (ControlToPaginate != null)) 536 { 537 OnPaginated(new EventArgs()); 538 } 539 } 540 541 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.Render"]/*' /> Render(HtmlTextWriter writer)542 protected override void Render(HtmlTextWriter writer) 543 { 544 MobilePage.EnterFormRender(this); 545 OnRender(writer); 546 MobilePage.ExitFormRender(); 547 } 548 PaginateForm()549 private int PaginateForm() 550 { 551 int pageWeight = MobilePage.Adapter.OptimumPageWeight; 552 if (Header != null) 553 { 554 pageWeight -= Header.VisibleWeight; 555 } 556 if (Footer != null) 557 { 558 pageWeight -= Footer.VisibleWeight; 559 } 560 if (pageWeight <= 0) 561 { 562 // 563 564 565 pageWeight = MobilePage.Adapter.OptimumPageWeight / 2; 566 } 567 568 if (IsFormPaginationAllowed()) 569 { 570 if ((Paginate) || (ControlToPaginate == this)) 571 { 572 ControlPager pager = new ControlPager(this, pageWeight); 573 base.PaginateRecursive(pager); 574 return pager.PageCount; 575 } 576 else if(ControlToPaginate != null) 577 { 578 ControlPager pager = new ControlPager(this, pageWeight); 579 SetControlPage(1); 580 Control control = ControlToPaginate; 581 MobileControl ctp = control as MobileControl; 582 if(ctp != null) 583 { 584 ctp.PaginateRecursive(pager); 585 } 586 else 587 { 588 int firstAssignedPage = -1; 589 DoPaginateChildren(pager, control, ref firstAssignedPage); 590 } 591 while(control != this) 592 { 593 MobileControl mc = control as MobileControl; 594 if(mc != null) 595 { 596 if(mc is Form) 597 { 598 throw(new Exception(SR.GetString(SR.Form_InvalidControlToPaginateForm))); 599 } 600 if (mc.FirstPage > ctp.FirstPage) 601 { 602 mc.FirstPage = ctp.FirstPage; 603 } 604 if(mc.LastPage < ctp.LastPage) 605 { 606 mc.LastPage = ctp.LastPage; 607 } 608 } 609 control = control.Parent; 610 } 611 this.LastPage = Math.Max(pager.PageCount, 1); 612 if(Header != null) 613 { 614 SetEnablePaginationRecursive(Header, false); 615 } 616 if(Footer != null) 617 { 618 SetEnablePaginationRecursive(Footer, false); 619 } 620 return this.LastPage; 621 } 622 } 623 624 return 1; 625 } 626 IsFormPaginationAllowed()627 private bool IsFormPaginationAllowed() 628 { 629 // AUI 4721 630 631 if (Action.Length == 0) 632 { 633 return true; 634 } 635 636 MobileCapabilities device = (MobileCapabilities)Page.Request.Browser; 637 String type = device.PreferredRenderingType; 638 bool javascriptSupported = device.JavaScript; 639 640 return javascriptSupported || 641 (type != MobileCapabilities.PreferredRenderingTypeHtml32 && 642 type != MobileCapabilities.PreferredRenderingTypeChtml10); 643 } 644 645 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PaginateRecursive"]/*' /> PaginateRecursive(ControlPager pager)646 public override void PaginateRecursive(ControlPager pager) 647 { 648 _pageCount = PaginateForm(); 649 } 650 651 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.PaginateChildren"]/*' /> 652 protected override bool PaginateChildren 653 { 654 get 655 { 656 return true; 657 } 658 } 659 660 private Control _controlToPaginate = null; 661 662 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.ControlToPaginate"]/*' /> 663 [ 664 Bindable(false), 665 Browsable(false), 666 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 667 ] 668 public Control ControlToPaginate 669 { 670 get 671 { 672 if(_controlToPaginate != null) 673 { 674 return _controlToPaginate; 675 } 676 if(ViewState["ControlToPaginate"] != null) 677 { 678 _controlToPaginate = Page.FindControl((ViewState["ControlToPaginate"]).ToString()); 679 } 680 return _controlToPaginate; 681 } 682 set 683 { 684 if(value != null) 685 { 686 ViewState["ControlToPaginate"] = value.UniqueID; 687 } 688 else 689 { 690 ViewState.Remove("ControlToPaginate"); 691 } 692 _controlToPaginate = value; 693 } 694 } 695 696 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.LoadPrivateViewState"]/*' /> LoadPrivateViewState(Object state)697 protected override void LoadPrivateViewState(Object state) 698 { 699 _currentPage = state != null ? (int)state : 1; 700 } 701 702 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.SavePrivateViewState"]/*' /> SavePrivateViewState()703 protected override Object SavePrivateViewState() 704 { 705 int currentPage = _currentPage; 706 if (currentPage > 1 && this == MobilePage.ActiveForm) 707 { 708 return currentPage; 709 } 710 else 711 { 712 return null; 713 } 714 } 715 716 /// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnDataBinding"]/*' /> OnDataBinding(EventArgs e)717 protected override void OnDataBinding(EventArgs e) 718 { 719 if(Script != null) 720 { 721 Script.DataBind(); 722 } 723 base.OnDataBinding(e); 724 } 725 726 private IPostBackEventHandler _defaultEventHandler = null; RegisterEventHandler(IPostBackEventHandler control)727 internal void RegisterEventHandler(IPostBackEventHandler control) 728 { 729 if (_defaultEventHandler == null) 730 { 731 _defaultEventHandler = control; 732 } 733 } 734 735 internal IPostBackEventHandler DefaultEventHandler 736 { 737 get 738 { 739 return _defaultEventHandler; 740 } 741 } 742 InvalidateParentStyles()743 internal override void InvalidateParentStyles() 744 { 745 PagerStyle.InvalidateParentStyle(); 746 base.InvalidateParentStyles(); 747 } 748 749 #region IPostBackEventHandler implementation IPostBackEventHandler.RaisePostBackEvent(String eventArgument)750 void IPostBackEventHandler.RaisePostBackEvent(String eventArgument) { 751 RaisePostBackEvent(eventArgument); 752 } 753 #endregion 754 } 755 756 /// <include file='doc\Form.uex' path='docs/doc[@for="FormControlBuilder"]/*' /> 757 [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 758 [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] 759 [Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")] 760 public class FormControlBuilder : LiteralTextContainerControlBuilder 761 { 762 /// <include file='doc\Form.uex' path='docs/doc[@for="FormControlBuilder.AppendSubBuilder"]/*' /> AppendSubBuilder(ControlBuilder subBuilder)763 public override void AppendSubBuilder(ControlBuilder subBuilder) 764 { 765 Type controlType = subBuilder.ControlType; 766 if(!( 767 (subBuilder.GetType().FullName == "System.Web.UI.CodeBlockBuilder") || 768 (typeof(MobileControl).IsAssignableFrom(controlType)) || 769 (typeof(UserControl).IsAssignableFrom(controlType)) || 770 (typeof(DeviceSpecific).IsAssignableFrom(controlType)) 771 )) 772 { 773 throw(new Exception(SR.GetString(SR.Form_InvalidSubControlType, subBuilder.TagName))); 774 } 775 base.AppendSubBuilder(subBuilder); 776 } 777 } 778 } 779