/// <summary>
        /// Set properties by enumerating the properties of an object.
        /// </summary>
        /// <param name="Object">The object to examine.</param>
        /// <param name="Callback">What to do afterwards.</param>
        /// <remarks>
        /// TO-DO: Evaluate dynamic properties if the object implements a certain interface?
        ///
        /// Dynamic properties would be properties that don't need to be owned by the object
        /// and cannot be modified, but should be displayed to the user anyway.
        ///
        /// The object would have to specify how to get the value for each dynamic property
        /// internally using an action; the action simply returns the object we want.
        ///
        /// The interface would expose a method that accepts the latter-described action,
        /// invokes it, and returns the resulting object (the current value of the
        /// dynamic property). Note, this enables you to calculate the value for the
        /// dynamic property however you like.
        ///
        /// If the object implements this interface, we can safely check for dynamic
        /// properties. While enumerating, we'd get the initial value; subsequently,
        /// we'd need a way of updating it when it should be (another TO-DO).
        ///
        /// Assuming each dynamic property specifies a general type, we'll know what type
        /// to cast to when retrieving the it's value.
        ///
        /// Ultimately, this would enable you to display properties in addition to the ones
        /// the object already owns without the additional overhead.
        /// </remarks>
        public async Task BeginFromObject(object Object, Action Callback = null)
        {
            await Task.Run(() =>
            {
                var Properties = Object.GetType().GetProperties();

                for (int i = 0, Length = Properties.Length; i < Length; i++)
                {
                    var Property = Properties[i];

                    var IsNested = false;
                    //If the type isn't explicitly supported...
                    if (!IsSupported(Property))
                    {
                        //...and it's not a reference type, skip it
                        if (Property.PropertyType.IsValueType)
                        {
                            continue;
                        }
                        //...and it is a reference type, consider it "nested"
                        else
                        {
                            IsNested = true;
                        }
                    }

                    var a = new PropertyAttributes()
                    {
                        { typeof(BrowsableAttribute), "Browsable", true },
                        { typeof(CategoryAttribute), "Category", string.Empty },
                        { typeof(ConstraintAttribute), null, null },
                        { typeof(DescriptionAttribute), "Description", string.Empty },
                        { typeof(DisplayNameAttribute), "DisplayName", string.Empty },
                        { typeof(FeaturedAttribute), "IsFeatured", false },
                        { typeof(Int64KindAttribute), "Kind", Int64Kind.Default },
                        { typeof(ReadOnlyAttribute), "IsReadOnly", false },
                        { typeof(StringKindAttribute), "Kind", StringKind.Default },
                        { typeof(StringFormatAttribute), "Format", string.Empty },
                    };

                    a.ExtractFrom(Property);

                    if (a.Get <BrowsableAttribute, bool>())
                    {
                        var Model = PropertyModel.New(Object, Property, a, IsNested);

                        if (Model != null)
                        {
                            Add(Model);
                        }
                    }
                }
            });

            Callback.InvokeIf(x => !x.IsNull());
        }
Esempio n. 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PropertyModel"/> class based on given data; some restrictions are observed.
        /// </summary>
        /// <param name="Host"></param>
        /// <param name="Property"></param>
        /// <param name="Attributes"></param>
        /// <returns></returns>
        internal static PropertyModel New(object Host, PropertyInfo Property, PropertyAttributes Attributes, bool IsNested)
        {
            var Result = New(IsNested ? typeof(object) : Property.PropertyType);

            if (Result != null)
            {
                Result.Info = Property;

                var Name = Attributes.Get <DisplayNameAttribute, string>();
                Name = Name.IsNullOrEmpty() ? Property.Name : Name;

                var Value = default(object);

                try
                {
                    //Will fail if locked
                    Value = Property.GetValue(Host);
                }
                catch (Exception)
                {
                    //Do nothing!
                }

                //Set the important stuff first
                Result.Host  = Host;
                Result.Name  = Name;
                Result.Value = Value;

                //Set the minor stuff
                Result.Category     = Attributes.Get <CategoryAttribute, string>();
                Result.Description  = Attributes.Get <DescriptionAttribute, string>();
                Result.StringFormat = Attributes.Get <StringFormatAttribute, string>();
                Result.IsFeatured   = Attributes.Get <FeaturedAttribute, bool>();

                //Honor the attribute if the property is settable; if it isn't, it is automatically readonly and should always be!
                if (Result.IsSettable)
                {
                    Result.IsReadOnly = Attributes.Get <ReadOnlyAttribute, bool>();
                }

                if (Result is PropertyModel <string> )
                {
                    Result.As <PropertyModel <string> >().Tag = Attributes.Get <StringKindAttribute, StringKind>();
                }

                if (Result is PropertyModel <long> )
                {
                    Result.As <PropertyModel <long> >().Tag = Attributes.Get <Int64KindAttribute, Int64Kind>();
                }

                //Honor constraints
                if (Result is ICoercable)
                {
                    var Constraint = Attributes.Get <ConstraintAttribute, ConstraintAttribute>();

                    if (Constraint != null)
                    {
                        Result.As <ICoercable>().SetConstraint(Constraint.Minimum, Constraint.Maximum);
                    }
                }
            }

            return(Result);
        }