File: DataAnnotations\DisplayAttribute.cs
Project: ndp\fx\src\xsp\system\DataAnnotations\System.ComponentModel.DataAnnotations.csproj (System.ComponentModel.DataAnnotations)
using System.ComponentModel.DataAnnotations.Resources;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
 
namespace System.ComponentModel.DataAnnotations {
    /// <summary>
    /// DisplayAttribute is a general-purpose attribute to specify user-visible globalizable strings for types and members.
    /// The string properties of this class can be used either as literals or as resource identifiers into a specified
    /// <see cref="ResourceType"/>
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Method, AllowMultiple = false)]
    public sealed class DisplayAttribute : Attribute {
        #region Member Fields
 
        private Type _resourceType;
        private LocalizableString _shortName = new LocalizableString("ShortName");
        private LocalizableString _name = new LocalizableString("Name");
        private LocalizableString _description = new LocalizableString("Description");
        private LocalizableString _prompt = new LocalizableString("Prompt");
        private LocalizableString _groupName = new LocalizableString("GroupName");
        private bool? _autoGenerateField;
        private bool? _autoGenerateFilter;
        private int? _order;
 
        #endregion
 
        #region All Constructors
 
        /// <summary>
        /// Default constructor for DisplayAttribute.  All associated string properties and methods will return <c>null</c>.
        /// </summary>
        public DisplayAttribute() {
        }
 
        #endregion
 
        #region Properties
 
        /// <summary>
        /// Gets or sets the ShortName attribute property, which may be a resource key string.
        /// <para>
        /// Consumers must use the <see cref="GetShortName"/> method to retrieve the UI display string.
        /// </para>
        /// </summary>
        /// <remarks>
        /// The property contains either the literal, non-localized string or the resource key
        /// to be used in conjunction with <see cref="ResourceType"/> to configure a localized
        /// short name for display.
        /// <para>
        /// The <see cref="GetShortName"/> method will return either the literal, non-localized
        /// string or the localized string when <see cref="ResourceType"/> has been specified.
        /// </para>
        /// </remarks>
        /// <value>
        /// The short name is generally used as the grid column label for a UI element bound to the member
        /// bearing this attribute.  A <c>null</c> or empty string is legal, and consumers must allow for that.
        /// </value>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public string ShortName {
            get {
                return this._shortName.Value;
            }
            set {
                if (this._shortName.Value != value) {
                    this._shortName.Value = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets the Name attribute property, which may be a resource key string.
        /// <para>
        /// Consumers must use the <see cref="GetName"/> method to retrieve the UI display string.
        /// </para>
        /// </summary>
        /// <remarks>
        /// The property contains either the literal, non-localized string or the resource key
        /// to be used in conjunction with <see cref="ResourceType"/> to configure a localized
        /// name for display.
        /// <para>
        /// The <see cref="GetName"/> method will return either the literal, non-localized
        /// string or the localized string when <see cref="ResourceType"/> has been specified.
        /// </para>
        /// </remarks>
        /// <value>
        /// The name is generally used as the field label for a UI element bound to the member
        /// bearing this attribute.  A <c>null</c> or empty string is legal, and consumers must allow for that.
        /// </value>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public string Name {
            get {
                return this._name.Value;
            }
            set {
                if (this._name.Value != value) {
                    this._name.Value = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets the Description attribute property, which may be a resource key string.
        /// <para>
        /// Consumers must use the <see cref="GetDescription"/> method to retrieve the UI display string.
        /// </para>
        /// </summary>
        /// <remarks>
        /// The property contains either the literal, non-localized string or the resource key
        /// to be used in conjunction with <see cref="ResourceType"/> to configure a localized
        /// description for display.
        /// <para>
        /// The <see cref="GetDescription"/> method will return either the literal, non-localized
        /// string or the localized string when <see cref="ResourceType"/> has been specified.
        /// </para>
        /// </remarks>
        /// <value>
        /// Description is generally used as a tool tip or description a UI element bound to the member
        /// bearing this attribute.  A <c>null</c> or empty string is legal, and consumers must allow for that.
        /// </value>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public string Description {
            get {
                return this._description.Value;
            }
            set {
                if (this._description.Value != value) {
                    this._description.Value = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets the Prompt attribute property, which may be a resource key string.
        /// <para>
        /// Consumers must use the <see cref="GetPrompt"/> method to retrieve the UI display string.
        /// </para>
        /// </summary>
        /// <remarks>
        /// The property contains either the literal, non-localized string or the resource key
        /// to be used in conjunction with <see cref="ResourceType"/> to configure a localized
        /// prompt for display.
        /// <para>
        /// The <see cref="GetPrompt"/> method will return either the literal, non-localized
        /// string or the localized string when <see cref="ResourceType"/> has been specified.
        /// </para>
        /// </remarks>
        /// <value>
        /// A prompt is generally used as a prompt or watermark for a UI element bound to the member
        /// bearing this attribute.  A <c>null</c> or empty string is legal, and consumers must allow for that.
        /// </value>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public string Prompt {
            get {
                return this._prompt.Value;
            }
            set {
                if (this._prompt.Value != value) {
                    this._prompt.Value = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets the GroupName attribute property, which may be a resource key string.
        /// <para>
        /// Consumers must use the <see cref="GetGroupName"/> method to retrieve the UI display string.
        /// </para>
        /// </summary>
        /// <remarks>
        /// The property contains either the literal, non-localized string or the resource key
        /// to be used in conjunction with <see cref="ResourceType"/> to configure a localized
        /// group name for display.
        /// <para>
        /// The <see cref="GetGroupName"/> method will return either the literal, non-localized
        /// string or the localized string when <see cref="ResourceType"/> has been specified.
        /// </para>
        /// </remarks>
        /// <value>
        /// A group name is used for grouping fields into the UI.  A <c>null</c> or empty string is legal,
        /// and consumers must allow for that.
        /// </value>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public string GroupName {
            get {
                return this._groupName.Value;
            }
            set {
                if (this._groupName.Value != value) {
                    this._groupName.Value = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets the <see cref="System.Type"/> that contains the resources for <see cref="ShortName"/>,
        /// <see cref="Name"/>, <see cref="Description"/>, <see cref="Prompt"/>, and <see cref="GroupName"/>.
        /// Using <see cref="ResourceType"/> along with these Key properties, allows the <see cref="GetShortName"/>,
        /// <see cref="GetName"/>, <see cref="GetDescription"/>, <see cref="GetPrompt"/>, and <see cref="GetGroupName"/>
        /// methods to return localized values.
        /// </summary>
        public Type ResourceType {
            get {
                return this._resourceType;
            }
            set {
                if (this._resourceType != value) {
                    this._resourceType = value;
 
                    this._shortName.ResourceType = value;
                    this._name.ResourceType = value;
                    this._description.ResourceType = value;
                    this._prompt.ResourceType = value;
                    this._groupName.ResourceType = value;
                }
            }
        }
 
        /// <summary>
        /// Gets or sets whether UI should be generated automatically to display this field. If this property is not
        /// set then the presentation layer will automatically determine whether UI should be generated. Setting this
        /// property allows an override of the default behavior of the presentation layer.
        /// <para>
        /// Consumers must use the <see cref="GetAutoGenerateField"/> method to retrieve the value, as this property getter will throw
        /// an exception if the value has not been set.
        /// </para>
        /// </summary>
        /// <exception cref="System.InvalidOperationException">
        /// If the getter of this property is invoked when the value has not been explicitly set using the setter.
        /// </exception>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public bool AutoGenerateField {
            get {
                if (!this._autoGenerateField.HasValue) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.DisplayAttribute_PropertyNotSet, "AutoGenerateField", "GetAutoGenerateField"));
                }
 
                return this._autoGenerateField.Value;
            }
            set {
                this._autoGenerateField = value;
            }
        }
 
        /// <summary>
        /// Gets or sets whether UI should be generated automatically to display filtering for this field. If this property is not
        /// set then the presentation layer will automatically determine whether filtering UI should be generated. Setting this
        /// property allows an override of the default behavior of the presentation layer.
        /// <para>
        /// Consumers must use the <see cref="GetAutoGenerateFilter"/> method to retrieve the value, as this property getter will throw
        /// an exception if the value has not been set.
        /// </para>
        /// </summary>
        /// <exception cref="System.InvalidOperationException">
        /// If the getter of this property is invoked when the value has not been explicitly set using the setter.
        /// </exception>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public bool AutoGenerateFilter {
            get {
                if (!this._autoGenerateFilter.HasValue) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.DisplayAttribute_PropertyNotSet, "AutoGenerateFilter", "GetAutoGenerateFilter"));
                }
 
                return this._autoGenerateFilter.Value;
            }
            set {
                this._autoGenerateFilter = value;
            }
        }
 
        /// <summary>
        /// Gets or sets the order in which this field should be displayed.  If this property is not set then
        /// the presentation layer will automatically determine the order.  Setting this property explicitly
        /// allows an override of the default behavior of the presentation layer.
        /// <para>
        /// Consumers must use the <see cref="GetOrder"/> method to retrieve the value, as this property getter will throw
        /// an exception if the value has not been set.
        /// </para>
        /// </summary>
        /// <exception cref="System.InvalidOperationException">
        /// If the getter of this property is invoked when the value has not been explicitly set using the setter.
        /// </exception>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The property and method are a matched pair")]
        public int Order {
            get {
                if (!this._order.HasValue) {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, DataAnnotationsResources.DisplayAttribute_PropertyNotSet, "Order", "GetOrder"));
                }
 
                return this._order.Value;
            }
            set {
                this._order = value;
            }
        }
 
        #endregion
 
        #region Methods
 
        /// <summary>
        /// Gets the UI display string for ShortName.
        /// <para>
        /// This can be either a literal, non-localized string provided to <see cref="ShortName"/> or the
        /// localized string found when <see cref="ResourceType"/> has been specified and <see cref="ShortName"/>
        /// represents a resource key within that resource type.
        /// </para>
        /// </summary>
        /// <returns>
        /// When <see cref="ResourceType"/> has not been specified, the value of
        /// <see cref="ShortName"/> will be returned.
        /// <para>
        /// When <see cref="ResourceType"/> has been specified and <see cref="ShortName"/>
        /// represents a resource key within that resource type, then the localized value will be returned.
        /// </para>
        /// <para>
        /// If <see cref="ShortName"/> is <c>null</c>, the value from <see cref="GetName"/> will be returned.
        /// </para>
        /// </returns>
        /// <exception cref="System.InvalidOperationException">
        /// After setting both the <see cref="ResourceType"/> property and the <see cref="ShortName"/> property,
        /// but a public static property with a name matching the <see cref="ShortName"/> value couldn't be found
        /// on the <see cref="ResourceType"/>.
        /// </exception>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public string GetShortName() {
            return this._shortName.GetLocalizableValue() ?? this.GetName();
        }
 
        /// <summary>
        /// Gets the UI display string for Name.
        /// <para>
        /// This can be either a literal, non-localized string provided to <see cref="Name"/> or the
        /// localized string found when <see cref="ResourceType"/> has been specified and <see cref="Name"/>
        /// represents a resource key within that resource type.
        /// </para>
        /// </summary>
        /// <returns>
        /// When <see cref="ResourceType"/> has not been specified, the value of
        /// <see cref="Name"/> will be returned.
        /// <para>
        /// When <see cref="ResourceType"/> has been specified and <see cref="Name"/>
        /// represents a resource key within that resource type, then the localized value will be returned.
        /// </para>
        /// <para>
        /// Can return <c>null</c> and will not fall back onto other values, as it's more likely for the
        /// consumer to want to fall back onto the property name.
        /// </para>
        /// </returns>
        /// <exception cref="System.InvalidOperationException">
        /// After setting both the <see cref="ResourceType"/> property and the <see cref="Name"/> property,
        /// but a public static property with a name matching the <see cref="Name"/> value couldn't be found
        /// on the <see cref="ResourceType"/>.
        /// </exception>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public string GetName() {
            return this._name.GetLocalizableValue();
        }
 
        /// <summary>
        /// Gets the UI display string for Description.
        /// <para>
        /// This can be either a literal, non-localized string provided to <see cref="Description"/> or the
        /// localized string found when <see cref="ResourceType"/> has been specified and <see cref="Description"/>
        /// represents a resource key within that resource type.
        /// </para>
        /// </summary>
        /// <returns>
        /// When <see cref="ResourceType"/> has not been specified, the value of
        /// <see cref="Description"/> will be returned.
        /// <para>
        /// When <see cref="ResourceType"/> has been specified and <see cref="Description"/>
        /// represents a resource key within that resource type, then the localized value will be returned.
        /// </para>
        /// </returns>
        /// <exception cref="System.InvalidOperationException">
        /// After setting both the <see cref="ResourceType"/> property and the <see cref="Description"/> property,
        /// but a public static property with a name matching the <see cref="Description"/> value couldn't be found
        /// on the <see cref="ResourceType"/>.
        /// </exception>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public string GetDescription() {
            return this._description.GetLocalizableValue();
        }
 
        /// <summary>
        /// Gets the UI display string for Prompt.
        /// <para>
        /// This can be either a literal, non-localized string provided to <see cref="Prompt"/> or the
        /// localized string found when <see cref="ResourceType"/> has been specified and <see cref="Prompt"/>
        /// represents a resource key within that resource type.
        /// </para>
        /// </summary>
        /// <returns>
        /// When <see cref="ResourceType"/> has not been specified, the value of
        /// <see cref="Prompt"/> will be returned.
        /// <para>
        /// When <see cref="ResourceType"/> has been specified and <see cref="Prompt"/>
        /// represents a resource key within that resource type, then the localized value will be returned.
        /// </para>
        /// </returns>
        /// <exception cref="System.InvalidOperationException">
        /// After setting both the <see cref="ResourceType"/> property and the <see cref="Prompt"/> property,
        /// but a public static property with a name matching the <see cref="Prompt"/> value couldn't be found
        /// on the <see cref="ResourceType"/>.
        /// </exception>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public string GetPrompt() {
            return this._prompt.GetLocalizableValue();
        }
 
        /// <summary>
        /// Gets the UI display string for GroupName.
        /// <para>
        /// This can be either a literal, non-localized string provided to <see cref="GroupName"/> or the
        /// localized string found when <see cref="ResourceType"/> has been specified and <see cref="GroupName"/>
        /// represents a resource key within that resource type.
        /// </para>
        /// </summary>
        /// <returns>
        /// When <see cref="ResourceType"/> has not been specified, the value of
        /// <see cref="GroupName"/> will be returned.
        /// <para>
        /// When <see cref="ResourceType"/> has been specified and <see cref="GroupName"/>
        /// represents a resource key within that resource type, then the localized value will be returned.
        /// </para>
        /// </returns>
        /// <exception cref="System.InvalidOperationException">
        /// After setting both the <see cref="ResourceType"/> property and the <see cref="GroupName"/> property,
        /// but a public static property with a name matching the <see cref="GroupName"/> value couldn't be found
        /// on the <see cref="ResourceType"/>.
        /// </exception>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public string GetGroupName() {
            return this._groupName.GetLocalizableValue();
        }
 
        /// <summary>
        /// Gets the value of <see cref="AutoGenerateField"/> if it has been set, or <c>null</c>.
        /// </summary>
        /// <returns>
        /// When <see cref="AutoGenerateField"/> has been set returns the value of that property.
        /// <para>
        /// When <see cref="AutoGenerateField"/> has not been set returns <c>null</c>.
        /// </para>
        /// </returns>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public bool? GetAutoGenerateField() {
            return this._autoGenerateField;
        }
 
        /// <summary>
        /// Gets the value of <see cref="AutoGenerateFilter"/> if it has been set, or <c>null</c>.
        /// </summary>
        /// <returns>
        /// When <see cref="AutoGenerateFilter"/> has been set returns the value of that property.
        /// <para>
        /// When <see cref="AutoGenerateFilter"/> has not been set returns <c>null</c>.
        /// </para>
        /// </returns>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public bool? GetAutoGenerateFilter() {
            return this._autoGenerateFilter;
        }
 
        /// <summary>
        /// Gets the value of <see cref="Order"/> if it has been set, or <c>null</c>.
        /// </summary>
        /// <returns>
        /// When <see cref="Order"/> has been set returns the value of that property.
        /// <para>
        /// When <see cref="Order"/> has not been set returns <c>null</c>.
        /// </para>
        /// </returns>
        /// <remarks>
        /// When an order is not specified, presentation layers should consider using the value
        /// of 10000.  This value allows for explicitly-ordered fields to be displayed before
        /// and after the fields that don't specify an order.
        /// </remarks>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does work using a property of the same name")]
        public int? GetOrder() {
            return this._order;
        }
 
        #endregion
    }
}