e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
612 lines
21 KiB
C#
612 lines
21 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="MobileControlDesigner.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Web.UI.Design.MobileControls
|
|
{
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Web.UI;
|
|
using System.Web.UI.Design;
|
|
using System.Web.UI.Design.MobileControls.Adapters;
|
|
using System.Web.UI.Design.MobileControls.Util;
|
|
using System.Web.UI.MobileControls;
|
|
|
|
[
|
|
System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand,
|
|
Flags=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)
|
|
]
|
|
[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.")]
|
|
internal class MobileControlDesigner :
|
|
ControlDesigner, IMobileDesigner, IDeviceSpecificDesigner
|
|
{
|
|
private bool _containmentStatusDirty = true;
|
|
private ContainmentStatus _containmentStatus;
|
|
private IDesignerHost _host;
|
|
private IWebFormsDocumentService _iWebFormsDocumentService;
|
|
private IMobileWebFormServices _iMobileWebFormServices;
|
|
private MobileControl _mobileControl;
|
|
private System.Windows.Forms.Control _header;
|
|
|
|
internal static readonly String resourceDllUrl =
|
|
"res://" + typeof(MobileControlDesigner).Module.FullyQualifiedName;
|
|
|
|
internal static readonly String errorIcon =
|
|
resourceDllUrl + "//ERROR_GIF";
|
|
|
|
internal static readonly String infoIcon =
|
|
resourceDllUrl + "//INFO_GIF";
|
|
|
|
internal static readonly String defaultErrorDesignTimeHTML =
|
|
@"
|
|
<table cellpadding=2 cellspacing=0 width='{4}' style='font-family:tahoma;font-size:8pt;color:buttontext;background-color:buttonface;border: solid 1px;border-top-color:buttonhighlight;border-left-color:buttonhighlight;border-bottom-color:buttonshadow;border-right-color:buttonshadow'>
|
|
<tr><td><span style='font-weight:bold'> {0}</span> - {1}</td></tr>
|
|
<tr><td>
|
|
<table style='font-family:tahoma;font-size:8pt;color:window;background-color:ButtonShadow'>
|
|
<tr>
|
|
<td valign='top'><img src={3} /></td>
|
|
<td width='100%'>{2}</td>
|
|
</tr>
|
|
</table>
|
|
</td></tr>
|
|
</table>
|
|
";
|
|
|
|
internal static readonly String _formPanelContainmentErrorMessage =
|
|
SR.GetString(SR.MobileControl_FormPanelContainmentErrorMessage);
|
|
|
|
internal static readonly String _mobilePageErrorMessage =
|
|
SR.GetString(SR.MobileControl_MobilePageErrorMessage);
|
|
|
|
internal static readonly String _topPageContainmentErrorMessage =
|
|
SR.GetString(SR.MobileControl_TopPageContainmentErrorMessage);
|
|
|
|
internal static readonly String _userControlWarningMessage =
|
|
SR.GetString(SR.MobileControl_UserControlWarningMessage);
|
|
|
|
private const String _appliedDeviceFiltersPropName = "AppliedDeviceFilters";
|
|
private const String _propertyOverridesPropName = "PropertyOverrides";
|
|
private const String _defaultDeviceSpecificIdentifier = "unique";
|
|
|
|
private static readonly string[] _nonBrowsableProperties = new string[] {
|
|
"EnableTheming",
|
|
"Expressions",
|
|
"SkinID",
|
|
};
|
|
|
|
// predefined constants used for mergingContext
|
|
internal const int MergingContextChoices = 0;
|
|
internal const int MergingContextTemplates = 1;
|
|
internal const int MergingContextProperties = 2;
|
|
|
|
[
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
|
|
Editor(typeof(AppliedDeviceFiltersTypeEditor), typeof(UITypeEditor)),
|
|
MergableProperty(false),
|
|
MobileCategory(SR.Category_DeviceSpecific),
|
|
MobileSysDescription(SR.MobileControl_AppliedDeviceFiltersDescription),
|
|
ParenthesizePropertyName(true),
|
|
]
|
|
protected String AppliedDeviceFilters
|
|
{
|
|
get
|
|
{
|
|
return String.Empty;
|
|
}
|
|
}
|
|
|
|
protected ContainmentStatus ContainmentStatus
|
|
{
|
|
get
|
|
{
|
|
if (!_containmentStatusDirty)
|
|
{
|
|
return _containmentStatus;
|
|
}
|
|
|
|
_containmentStatus =
|
|
DesignerAdapterUtil.GetContainmentStatus(_mobileControl);
|
|
|
|
_containmentStatusDirty = false;
|
|
return _containmentStatus;
|
|
}
|
|
}
|
|
|
|
internal Object DesignTimeElementInternal
|
|
{
|
|
get
|
|
{
|
|
return typeof(HtmlControlDesigner).InvokeMember("DesignTimeElement",
|
|
BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic,
|
|
null, this, null, CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
|
|
public override bool DesignTimeHtmlRequiresLoadComplete
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private IDesignerHost Host
|
|
{
|
|
get
|
|
{
|
|
if (_host != null)
|
|
{
|
|
return _host;
|
|
}
|
|
_host = (IDesignerHost)GetService(typeof(IDesignerHost));
|
|
Debug.Assert(_host != null);
|
|
return _host;
|
|
}
|
|
}
|
|
|
|
internal IMobileWebFormServices IMobileWebFormServices
|
|
{
|
|
get
|
|
{
|
|
if (_iMobileWebFormServices == null)
|
|
{
|
|
_iMobileWebFormServices =
|
|
(IMobileWebFormServices)GetService(typeof(IMobileWebFormServices));
|
|
}
|
|
|
|
return _iMobileWebFormServices;
|
|
}
|
|
}
|
|
|
|
private IWebFormsDocumentService IWebFormsDocumentService
|
|
{
|
|
get
|
|
{
|
|
if (_iWebFormsDocumentService == null)
|
|
{
|
|
_iWebFormsDocumentService =
|
|
(IWebFormsDocumentService)GetService(typeof(IWebFormsDocumentService));
|
|
|
|
Debug.Assert(_iWebFormsDocumentService != null);
|
|
}
|
|
|
|
return _iWebFormsDocumentService;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Indicates whether the initial page load is completed
|
|
/// </summary>
|
|
protected bool LoadComplete
|
|
{
|
|
get
|
|
{
|
|
return !IWebFormsDocumentService.IsLoading;
|
|
}
|
|
}
|
|
|
|
[
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
|
|
Editor(typeof(PropertyOverridesTypeEditor), typeof(UITypeEditor)),
|
|
MergableProperty(false),
|
|
MobileCategory(SR.Category_DeviceSpecific),
|
|
MobileSysDescription(SR.MobileControl_DeviceSpecificPropsDescription),
|
|
ParenthesizePropertyName(true),
|
|
]
|
|
protected String PropertyOverrides
|
|
{
|
|
get
|
|
{
|
|
return String.Empty;
|
|
}
|
|
}
|
|
|
|
private bool ValidContainment
|
|
{
|
|
get
|
|
{
|
|
return (
|
|
ContainmentStatus == ContainmentStatus.InForm ||
|
|
ContainmentStatus == ContainmentStatus.InPanel ||
|
|
ContainmentStatus == ContainmentStatus.InTemplateFrame);
|
|
}
|
|
}
|
|
|
|
protected virtual String GetErrorMessage(out bool infoMode)
|
|
{
|
|
infoMode = false;
|
|
|
|
// Skip containment checking if the control is placed in MobileUserControl
|
|
if (!DesignerAdapterUtil.InMobileUserControl(_mobileControl))
|
|
{
|
|
if (DesignerAdapterUtil.InUserControl(_mobileControl))
|
|
{
|
|
infoMode = true;
|
|
return MobileControlDesigner._userControlWarningMessage;
|
|
}
|
|
|
|
if (!DesignerAdapterUtil.InMobilePage(_mobileControl))
|
|
{
|
|
return _mobilePageErrorMessage;
|
|
}
|
|
|
|
if (!ValidContainment)
|
|
{
|
|
return _formPanelContainmentErrorMessage;
|
|
}
|
|
}
|
|
|
|
bool containsTag;
|
|
bool containsDataboundLiteral;
|
|
_mobileControl.GetControlText(out containsTag, out containsDataboundLiteral);
|
|
|
|
if (containsTag)
|
|
{
|
|
return SR.GetString(SR.MobileControl_InnerTextCannotContainTagsDesigner);
|
|
}
|
|
|
|
// Containment is valid, return null;
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>
|
|
/// Gets the HTML to be used for the design time representation of the control runtime.
|
|
/// </para>
|
|
/// </summary>
|
|
/// <returns>
|
|
/// <para>
|
|
/// The design time HTML.
|
|
/// </para>
|
|
/// </returns>
|
|
public sealed override String GetDesignTimeHtml()
|
|
{
|
|
if (!LoadComplete)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
bool infoMode = false;
|
|
String errorMessage = GetErrorMessage(out infoMode);
|
|
SetStyleAttributes();
|
|
|
|
if (null != errorMessage)
|
|
{
|
|
return GetDesignTimeErrorHtml(errorMessage, infoMode);
|
|
}
|
|
|
|
String designTimeHTML = null;
|
|
try
|
|
{
|
|
designTimeHTML = GetDesignTimeNormalHtml();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.Fail(ex.ToString());
|
|
designTimeHTML = GetDesignTimeErrorHtml(ex.Message, false);
|
|
}
|
|
|
|
return designTimeHTML;
|
|
}
|
|
|
|
protected virtual String GetDesignTimeNormalHtml()
|
|
{
|
|
return GetEmptyDesignTimeHtml();
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>
|
|
/// Gets the HTML to be used at design time as the representation of the
|
|
/// control when the control runtime does not return any rendered
|
|
/// HTML. The default behavior is to return a string containing the name
|
|
/// of the component.
|
|
/// </para>
|
|
/// </summary>
|
|
/// <returns>
|
|
/// <para>
|
|
/// The name of the component, by default.
|
|
/// </para>
|
|
/// </returns>
|
|
protected override String GetEmptyDesignTimeHtml()
|
|
{
|
|
return "<div style='width:100%'>" + base.GetEmptyDesignTimeHtml() + "</div>";
|
|
}
|
|
|
|
protected override sealed String GetErrorDesignTimeHtml(Exception e)
|
|
{
|
|
return base.GetErrorDesignTimeHtml(e);
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
protected virtual String GetDesignTimeErrorHtml(String errorMessage, bool infoMode)
|
|
{
|
|
return DesignerAdapterUtil.GetDesignTimeErrorHtml(
|
|
errorMessage, infoMode, _mobileControl, Behavior, ContainmentStatus);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>
|
|
/// Gets the HTML to be persisted for the content present within the associated server control runtime.
|
|
/// </para>
|
|
/// </summary>
|
|
/// <returns>
|
|
/// <para>
|
|
/// Persistable Inner HTML.
|
|
/// </para>
|
|
/// </returns>
|
|
public override String GetPersistInnerHtml()
|
|
{
|
|
if (!IsDirty)
|
|
{
|
|
// Returning a null string will prevent the actual save.
|
|
return null;
|
|
}
|
|
|
|
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
|
|
|
|
// HACK ALERT:
|
|
// We need to temporarily swap out the Text property to avoid being
|
|
// persisted into control inner text. However, setting the Text property
|
|
// will wipe out all control collections, therefore we need to cache
|
|
// the Text value too.
|
|
bool hasControls = _mobileControl.HasControls();
|
|
if ((_mobileControl is TextControl || _mobileControl is TextView)
|
|
&& hasControls)
|
|
{
|
|
String originalText = null;
|
|
Control[] children = null;
|
|
|
|
// Cache all child controls here.
|
|
children = new Control[_mobileControl.Controls.Count];
|
|
_mobileControl.Controls.CopyTo(children, 0);
|
|
|
|
// Replace the text with empty string.
|
|
if (_mobileControl is TextControl)
|
|
{
|
|
originalText = ((TextControl)_mobileControl).Text;
|
|
((TextControl)_mobileControl).Text = String.Empty;
|
|
}
|
|
else
|
|
{
|
|
originalText = ((TextView)_mobileControl).Text;
|
|
((TextView)_mobileControl).Text = String.Empty;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Persist inner properties without Text property.
|
|
MobileControlPersister.PersistInnerProperties(sw, _mobileControl, Host);
|
|
// Persist the child collections.
|
|
foreach (Control c in children)
|
|
{
|
|
MobileControlPersister.PersistControl(sw, c, Host);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
// Write the original text back to control.
|
|
if (_mobileControl is TextControl)
|
|
{
|
|
((TextControl)_mobileControl).Text = originalText;
|
|
}
|
|
else
|
|
{
|
|
((TextView)_mobileControl).Text = originalText;
|
|
}
|
|
|
|
// Add the child controls back.
|
|
foreach (Control c in children)
|
|
{
|
|
_mobileControl.Controls.Add(c);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MobileControlPersister.PersistInnerProperties(sw, _mobileControl, Host);
|
|
}
|
|
|
|
IsDirty = false;
|
|
return sw.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>
|
|
/// Initializes the designer with the component for design.
|
|
/// </para>
|
|
/// </summary>
|
|
/// <param name='component'>
|
|
/// The control element for design.
|
|
/// </param>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This is called by the designer host to establish the component for
|
|
/// design.
|
|
/// </para>
|
|
/// </remarks>
|
|
/// <seealso cref='System.ComponentModel.Design.IDesigner'/>
|
|
public override void Initialize(IComponent component)
|
|
{
|
|
Debug.Assert(component is System.Web.UI.MobileControls.MobileControl,
|
|
"MobileControlDesigner.Initialize - Invalid MobileControl Control");
|
|
|
|
base.Initialize(component);
|
|
|
|
_mobileControl = (System.Web.UI.MobileControls.MobileControl) component;
|
|
}
|
|
|
|
protected virtual void SetStyleAttributes()
|
|
{
|
|
//Debug.Assert(Behavior != null, "Behavior is null, Load completed? " + LoadComplete.ToString());
|
|
|
|
DesignerAdapterUtil.SetStandardStyleAttributes(Behavior, ContainmentStatus);
|
|
}
|
|
|
|
public override void OnComponentChanged(Object sender, ComponentChangedEventArgs ce)
|
|
{
|
|
// Delegate to the base class implementation first!
|
|
base.OnComponentChanged(sender, ce);
|
|
|
|
MemberDescriptor member = ce.Member;
|
|
if (member != null &&
|
|
member.GetType().FullName.Equals(Constants.ReflectPropertyDescriptorTypeFullName))
|
|
{
|
|
PropertyDescriptor propDesc = (PropertyDescriptor)member;
|
|
String propName = propDesc.Name;
|
|
|
|
if ((_mobileControl is TextControl || _mobileControl is TextView)
|
|
&& propName.Equals("Text"))
|
|
{
|
|
_mobileControl.Controls.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>
|
|
/// Notification that is called when the associated control is parented.
|
|
/// </para>
|
|
/// </summary>
|
|
public override void OnSetParent()
|
|
{
|
|
base.OnSetParent();
|
|
|
|
_containmentStatusDirty = true;
|
|
if (LoadComplete)
|
|
{
|
|
UpdateRendering();
|
|
}
|
|
}
|
|
|
|
protected override void PreFilterProperties(IDictionary properties)
|
|
{
|
|
base.PreFilterProperties(properties);
|
|
|
|
properties[_appliedDeviceFiltersPropName] =
|
|
TypeDescriptor.CreateProperty(this.GetType(), _appliedDeviceFiltersPropName, typeof(String));
|
|
|
|
properties[_propertyOverridesPropName] =
|
|
TypeDescriptor.CreateProperty(this.GetType(), _propertyOverridesPropName, typeof(String));
|
|
|
|
foreach (string propertyName in _nonBrowsableProperties) {
|
|
PropertyDescriptor property = (PropertyDescriptor) properties[propertyName];
|
|
Debug.Assert(property != null, "Property is null: " + propertyName);
|
|
if (property != null) {
|
|
properties[propertyName] = TypeDescriptor.CreateProperty(this.GetType(), property, BrowsableAttribute.No);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* IMobileDesigner INTERFACE IMPLEMENTATION
|
|
*/
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public void UpdateRendering()
|
|
{
|
|
_mobileControl.RefreshStyle();
|
|
|
|
UpdateDesignTimeHtml();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Begin IDeviceSpecificDesigner Implementation
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void IDeviceSpecificDesigner.SetDeviceSpecificEditor
|
|
(IRefreshableDeviceSpecificEditor editor)
|
|
{
|
|
}
|
|
|
|
String IDeviceSpecificDesigner.CurrentDeviceSpecificID
|
|
{
|
|
get
|
|
{
|
|
return _defaultDeviceSpecificIdentifier;
|
|
}
|
|
}
|
|
|
|
System.Windows.Forms.Control IDeviceSpecificDesigner.Header
|
|
{
|
|
get
|
|
{
|
|
return _header;
|
|
}
|
|
}
|
|
|
|
System.Web.UI.Control IDeviceSpecificDesigner.UnderlyingControl
|
|
{
|
|
get
|
|
{
|
|
return _mobileControl;
|
|
}
|
|
}
|
|
|
|
Object IDeviceSpecificDesigner.UnderlyingObject
|
|
{
|
|
get
|
|
{
|
|
return _mobileControl;
|
|
}
|
|
}
|
|
|
|
void IDeviceSpecificDesigner.InitHeader(int mergingContext)
|
|
{
|
|
HeaderPanel panel = new HeaderPanel();
|
|
HeaderLabel lblDescription = new HeaderLabel();
|
|
|
|
lblDescription.TabIndex = 0;
|
|
lblDescription.Text = SR.GetString(
|
|
SR.MobileControl_SettingGenericChoiceDescription
|
|
);
|
|
panel.Height = lblDescription.Height;
|
|
panel.Width = lblDescription.Width;
|
|
panel.Controls.Add(lblDescription);
|
|
_header = panel;
|
|
}
|
|
|
|
void IDeviceSpecificDesigner.RefreshHeader(int mergingContext)
|
|
{
|
|
}
|
|
|
|
bool IDeviceSpecificDesigner.GetDeviceSpecific(String deviceSpecificParentID, out DeviceSpecific ds)
|
|
{
|
|
Debug.Assert(_defaultDeviceSpecificIdentifier == deviceSpecificParentID);
|
|
ds = ((MobileControl) _mobileControl).DeviceSpecific;
|
|
return true;
|
|
}
|
|
|
|
void IDeviceSpecificDesigner.SetDeviceSpecific(String deviceSpecificParentID, DeviceSpecific ds)
|
|
{
|
|
Debug.Assert(_defaultDeviceSpecificIdentifier == deviceSpecificParentID);
|
|
if (null != ds)
|
|
{
|
|
ds.SetOwner((MobileControl) _mobileControl);
|
|
}
|
|
_mobileControl.DeviceSpecific = ds;
|
|
}
|
|
|
|
void IDeviceSpecificDesigner.UseCurrentDeviceSpecificID()
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// End IDeviceSpecificDesigner Implementation
|
|
////////////////////////////////////////////////////////////////////////
|
|
}
|
|
}
|