/// <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()); }
/// <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); }