/// <summary>
        /// Creates and returns a generic ItemsGridControl container for an IModelEntity class collection datasource.
        /// Optionally, a list of explicit Property Tech-Name plus DataGridColumn (null for hide) pairs can be specified (to be attached for matching Context entity properties).
        /// </summary>
        public static ItemsGridMaintainer <TEntity, TItem> CreateItemsGridControl <TEntity, TItem>(TEntity DataSourceOwner, IList <TItem> DataSource, Func <object, bool> DirectEditingConfirmator,
                                                                                                   params Tuple <string, DataGridColumn>[] ColumnControls)
            where TEntity : class, IModelEntity
            where TItem : class, IModelEntity
        {
            // Create columns
            var Definitor         = MModelClassDefinitor.GetDefinitor(typeof(TItem));
            var ColDefs           = new List <Tuple <IIdentifiableElement, DataGridColumn> >(Definitor.Properties.Count());
            var DisplayProperties = Definitor.Properties.OrderBy(prop => !prop.IsEditControlled).ThenBy(prop => prop.IsAdvanced);

            foreach (var Property in DisplayProperties)
            {
                if (Property.IsDirectlyEditable)
                {
                    var ExplicitColumnControl = (ColumnControls == null ? null : ColumnControls.FirstOrDefault(colctl => colctl.Item1 == Property.TechName));

                    if (ExplicitColumnControl == null)
                    {
                        ColDefs.Add(Tuple.Create <IIdentifiableElement, DataGridColumn>(Property, CreateGridColumn(DataSourceOwner, Property)));
                    }
                    else
                    if (ExplicitColumnControl.Item2 != null)
                    {
                        ColDefs.Add(Tuple.Create <IIdentifiableElement, DataGridColumn>(Property, ExplicitColumnControl.Item2));
                    }
                }
            }

            // Call the control creator.
            var Result = CreateItemsGridMaintainer(DataSourceOwner, DataSource, DirectEditingConfirmator, ColDefs.ToArray());

            return(Result);
        }
Beispiel #2
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public ModelClassDefinitor(string TechName, MModelClassDefinitor AncestorDefinitor = null,
                            string Name = "", string Summary = "" /*- ,
                                                                   * Func<TModelClass, IList<string>> InstanceValidator = null*/)
     : base(TechName, Name, Summary, typeof(TModelClass), AncestorDefinitor)
 {
     this.RegisterDefinitor(this);
     //- this.InstanceValidator = InstanceValidator;
 }
 /// <summary>
 /// Register a model-class type as exposed to template-based extraction (such as code generation).
 /// Accepts a list of explicit Members to be exposed.
 /// </summary>
 internal static Tuple <Type, bool, string[], string[]> ExposeForTemplateBasedExtraction(MModelClassDefinitor ClassDefinitor,
                                                                                         bool IsGenericBase = false, params string[] ExplicitMembers)
 {
     return(ExposeForTemplateBasedExtraction(ClassDefinitor.DeclaringType, IsGenericBase, ExplicitMembers));
 }
 /// <summary>
 /// Register the owner declarator of this member/definitor and assemble any related behaviors (such as setter interception).
 /// </summary>
 internal override void AssignDeclarator(MModelClassDefinitor DeclaringDefinitor)
 {
     this.DeclaringDefinitor = DeclaringDefinitor;
 }
Beispiel #5
0
        /// <summary>
        /// Populates properties of a target model instance, plus returning it, with these from the supplied one.
        /// </summary>
        /// <param name="Target">Target model instance for which populate/overwrite property values.</param>
        /// <param name="Source">Source model instance from which get property values.</param>
        ///
        /// <param name="TargetOwner">Model instance owning the Target (intended to update owner references of the Source).</param>
        /// <param name="CloningScope">Indicates to make a copy of the populated value through the dependant object hierarchy.</param>
        /// <param name="IsForCloning">Indicates whether the population will be performed on a clone.</param>  // See below
        /// <param name="AsActive">Indicates whether the new clone will be active (i.e. will notify changes and store them for undo/redo).</param>
        /// <param name="MemberNames">Optional explicit member names to be populated (when empty, all members are populated).</param>
        /// <returns>The populated target model instance.</returns>
        public TModelClass PopulateInstance(TModelClass Target, TModelClass Source, IMModelClass TargetOwner,
                                            ECloneOperationScope CloningScope = ECloneOperationScope.Slight,
                                            bool IsForCloning = false, bool AsActive = true, params string[] MemberNames)
        {
            General.ContractRequiresNotNull(Target, Source);

            if (!AsActive)
            {
                MModelClassDefinitor.RegisterPassiveInstance(Target);
            }

            /*T
             * var SouCD = Source.ClassDefinition;
             * var TarCD = Target.ClassDefinition;
             * var AreEq = (SouCD == TarCD);
             *
             * string PopulatingKind = null;
             *
             * var PopulatingPrefix = " ".Replicate(PopulationLevel * 2);
             *
             * if (Target is IMModelEntityAgent)
             *  PopulatingKind = "ENT->AGT";
             * else
             *  PopulatingKind = "AGT->ENT";
             *
             * Console.WriteLine(PopulatingPrefix + "AT-POPULATE (" + PopulatingKind + ")... Source=[{0}:{1}], Target=[{2}:{3}], ClassDefsAreEqual=[{4}], Scope={5}, Members={6}",
             *                SouCD, Source.GetHashCode(), TarCD, Target.GetHashCode(), AreEq, CloningScope,
             *                (MemberNames == null || MemberNames.Length < 1 ? "<ALL>" : MemberNames.GetConcatenation(null,";"))); */

            if (!Target.ClassDefinition.DeclaringType.InheritsFrom(this.DeclaringType))
            {
                throw new UsageAnomaly("The supplied Target instance is not defined by this model class definitor",
                                       new DataWagon("target-ClassDef", this).Add("Target instance", Target));
            }

            if (!this.IsCompatibleClassDefinition(Source.ClassDefinition))
            {
                throw new UsageAnomaly("Cannot populate a model class instance from an incompatible one (must be of the same type or descendant of it)",
                                       new DataWagon("target-ClassDef", this).Add("source-ClassDef", Source.ClassDefinition));
            }

            // Determine properties to be populated
            var TargetProperties = (MemberNames == null || MemberNames.Length < 1
                                    ? Source.ClassDefinition.Properties    // IMPORTANT: Do not use 'this.Collections' (that way descendants members are not considered!)
                                    : Source.ClassDefinition.Properties.Where(prop => prop.TechName.IsOneOf(MemberNames)));

            // First, populate relevant properties, such as owner referencers
            var InitialProperties = TargetProperties.Where(prop => prop.ReferencesOwner.HasValue).ToArray();

            // PENDING: Treat Sub-Owners properly (reappoint cloned references to the cloned sub-owners, not to the original ones)
            PopulateProperties(Target, Source, (CloningScope == ECloneOperationScope.DeepAndEquivalent ? null : TargetOwner),
                               CloningScope, IsForCloning, InitialProperties);

            // Second, populate all collections (some of the remaining properties depends on some of them)
            var TargetCollections = (MemberNames == null || MemberNames.Length < 1
                                     ? Source.ClassDefinition.Collections   // IMPORTANT: Do not use 'this.Collections' (that way descendants members are not considered!)
                                     : Source.ClassDefinition.Collections.Where(coll => coll.TechName.IsOneOf(MemberNames))).ToArray();

            foreach (var CollDef in TargetCollections)
            {
                var TargetCollection = (EditableCollection)CollDef.Read(Target);
                var SourceCollection = (EditableCollection)CollDef.Read(Source);

                /*T if (TargetCollection != null && TargetCollection.Name == "MarkerDefinitions")
                 * {
                 *  Console.WriteLine(CallingPrefix + "........................................................................");
                 *  Console.WriteLine(CallingPrefix + "MarkerDefs are the same: {0}", TargetCollection.IsEqual(SourceCollection));
                 *  Console.WriteLine(CallingPrefix + "Source: HC={0}, ItemsCnt={1}", SourceCollection.GetHashCode(), SourceCollection.Count);
                 *  Console.WriteLine(CallingPrefix + "Target: HC={0}, ItemsCnt={1}", TargetCollection.GetHashCode(), TargetCollection.Count);
                 * } */

                /*T if (TargetCollection != null && TargetCollection.Name == "TextFormats")
                 * {
                 *  Console.WriteLine("Populating coll TextFormats >>>>>>>>>>>>>>>>>>>>>");
                 *  Console.WriteLine("SourceEnt: {0}, TargetEnt: {1}", Source.GetHashCode(), Target.GetHashCode());
                 *  Console.WriteLine("TextFormats are the same: {0}", TargetCollection.IsEqual(SourceCollection));
                 *  Console.WriteLine("SourceColl: HC={0}, ItemsCnt={1}", SourceCollection.GetHashCode(), SourceCollection.Count);
                 *  Console.WriteLine("TargetColl: HC={0}, ItemsCnt={1}", TargetCollection.GetHashCode(), TargetCollection.Count);
                 *  Console.WriteLine("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
                 * } */

                if (SourceCollection == null)
                {
                    CollDef.Write(Target, SourceCollection);
                    continue;
                }

                // IMPORTANT: Remember that SourceCollection, if not cloned,
                // will still be pointing to its original Variating-Instance.

                var DoClone = CollDef.IsCloneableFor(CloningScope, Source);
                if (DoClone.Item1)
                {
                    //T PopulationLevel++;
                    CollDef.Write(Target, SourceCollection.DuplicateFor(Target as IModelEntity, Target, DoClone.Item2));
                    //T PopulationLevel--;
                }
                else
                {
                    CollDef.Write(Target, SourceCollection);    //? Consider: TargetCollection.UpdateContentFrom(SourceCollection);
                }
            }

            // Third, populate the remaining properties (remember that some of these depend on collections)
            var RemainingProperties = TargetProperties.Where(prop => !prop.ReferencesOwner.HasValue).ToArray();

            PopulateProperties(Target, Source, (CloningScope == ECloneOperationScope.DeepAndEquivalent ? null : TargetOwner),
                               CloningScope, IsForCloning, RemainingProperties);

            if (CloningScope != ECloneOperationScope.DeepAndEquivalent)
            {
                // Generate new GUID for Unique-Element's Global-Id.
                var TargetElement = Target as UniqueElement;
                if (TargetElement != null)
                {
                    TargetElement.GlobalId = Guid.NewGuid();
                }
            }

            return(Target);
        }