none
Designers & Serialization RRS feed

  • Question

  • Hello Experts,

    I am developing a component to represent command line functionality (flag definitions, etc.)  I am currently using Visual Studio 2015 on Windows 7.

    I have tagged my command line component with a custom CodeDomSerializer of which I have overridden the Deserialize() and Serialize() methods.  When serializing I have 2 issues:

    1. Old flag fields persist in the .Designer file
    2. I want to be able to write properties in the .Designer file to return the flag names as strings

    The generated .Designer file looks like

    namespace MyNamespace
    {
        partial class ApplicationLogistics
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary> 
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Component Designer generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.components = new System.ComponentModel.Container();
                this._commandLine = new MyNamespace.CommandLine(this.components);
                this._flag_flag4z = "-flag4z";
                this._flag_flag3long = "-flag3long";
                this._flag_myFlag12 = "-myFlag12";
                this._flag_myFlag2 = "-myFlag2";
                // 
                // _commandLine
                // 
                this._commandLine.ApplicationName = "HelloWorld4567";
                this._commandLine.EmptyBehvior = MyNamespace.CommandLineEmptyBehaviorEnum.DisplayApplictionStub;
                this._commandLine.MutualFlagExclusionSetInitializations = new MyNamespace.ICommandLineMutualFlagExclusionSet[0];
                this._commandLine.ReportableComponents = ((MyNamespace.CommandLineReportableComponentsEnum)((MyNamespace.CommandLineReportableComponentsEnum.FlagPrototype | MyNamespace.CommandLineReportableComponentsEnum.FlagDescriptions)));
                this._commandLine.ReportWidth = 85;
                // 
                // Adding standard flag definitions
                // 
                _commandLine.AddStandardFlagDef(typeof(System.DateTime), this._flag_flag4z, "ddd4", "value", 0, 2, 0, 8, new char[] {
                ',',
                ':'});
                _commandLine.AddStandardFlagDef(typeof(ulong), this._flag_flag3long, "My Flag 3 long descdription.", "mailbox", 3, 15, 6, 15, new char[] {
                ';'});
                _commandLine.AddStandardFlagDef(typeof(string), this._flag_myFlag12, "desc 1", "value", 0, null, 0, null, new char[] {
                '#'});
                _commandLine.AddStandardFlagDef(typeof(char), this._flag_myFlag2, "Use this flag to specify that you want to do something with the ith value.", "value", 0, 1, 0, 1, new char[] {
                ','});
                // 
                // Adding null-flag definitions
                // 
                _commandLine.AddNullFlagDef("-null1", "gsdfg", 0, 1);
                // 
                // Adding value-only flag definitions
                // 
                _commandLine.AddValueOnlyFlagDef(typeof(double), "val1", "wert", 1, 1, 1, null, new char[] {
                ','});
                _commandLine.AddValueOnlyFlagDef(typeof(string), "val2", "sdfgsdf", 0, null, 0, null, new char[] {
                ','});
            }
    
            #endregion
    
            public CommandLine _commandLine;
            private string _flag_flag4ab;
            private string _flag_flag4abc;
            private string _flag_flag4x;
            private string _flag_flag3long;
            private string _flag_myFlag12;
            private string _flag_myFlag2;
            private string _flag_flag4y;
            private string _flag_flag4z;
        }
    }
    

    First issue:

    The bolded flags persist when they should not, i.e. I started with flag4ab and then changed it to flag4abc then to flag4x then to flag4y then to flag4z.  The flag that should be defined is flag4z but all the previous incarnations remain.  In my

    override object Serialize(IDesignerSerializationManagermanager, objectvalue)

    I have stepped through in the debugger and have looked throughout all the CodeStatementCollections and Contexts in 'manager' and can find no vestigial remnants of these flags.  So, I have no idea where they are coming from.

    Second issue:

    I would actually like to have my flag names defined as

            public CommandLine _commandLine;
            public const string _flag_flag3long = "flag3long";
            public const string _flag_myFlag12 = "myFlag12";
            public const string _flag_myFlag2 = "myFlag2";
            public const string _flag_flag4z = "flag4z";
    
     

    but this doesn't seem to possible as the 'static' and 'const' keywords as well as the

    CodeMemberField.InitExpression

    directive appear to be disabled .  What I tried was

    CodeMemberField fldNameDecl = new CodeMemberField(typeof(string), "_flag_flag4z") { Attributes = MemberAttributes.Public| MemberAttributes.Const, InitExpression = new CodePrimitiveExpression("flag4z") };

    CodeTypeDeclaration typeDecl = manager.Context[typeof(CodeTypeDeclaration)] asCodeTypeDeclaration;

    typeDecl?.Members.Add(fldNameDecl);


    If there is a way to accomplish the static flag definitions I would very much appreciate it.

    In lieu of static flag definitions, I can create private flag name fields and then set them in the generated code.  I do want to make these fields public; so, I have opted to create properties to return these fields.  It would be desirable to write these out in the .Designer file automatically but as of now they have to be coded manually in the code file.

    I am not sure where to turn or look.  There has to be a way.

    Can anyone shed some insight on how to work with designers and serializers to customize .Designer files?

    Thank you

    Thursday, August 1, 2019 11:46 PM

All replies

  • Hi TonyArch,

    Thank you for posting here.

    Based on your code, I have a question to confirm with you.

    What's the type of your application? Winform? WPF? It will help us to analyze your problem quickly.

    We are waiting for your update.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, August 2, 2019 9:25 AM
    Moderator
  • Hi Xingyu,

    All development has been in the component designer (typically associated with Winforms).  The idea is to unify application logistical behavior for displaying help, processing command lines, etc.  To this end people can create an ApplicationLogistics component in the component designer and bring in (in this case) a CommandLine component that can be configured with flags, etc.  With this ApplicationLogistics defined it could feasibly be used anywhere.  But the area where the problems are seem to be within the world of the component designer and custom designers and serializers (CodeDomSerializer).

    The code for Deserialize and Serialize in my custom CodeDomSerializer is as follows:

            public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
            {
                // This is how we associate the component with the serializer.
                CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
                GetSerializer(typeof(CommandLine).BaseType, typeof(CodeDomSerializer));
    
                /* This is the simplest case, in which the class just calls the base class to do the work. */
                CommandLine oCommandLine = (CommandLine)baseClassSerializer.Deserialize(manager, codeObject);
    
                oCommandLine.ClearAll();
    
                string oName = manager.GetName(oCommandLine);
    
                CodeStatementCollection statements = codeObject as CodeStatementCollection;
    
                if(statements != null)
                {
                    if(statements.OfType<CodeVariableDeclarationStatement>().Count(vDecl => vDecl.Name == oName) > 0)
                    {
                        SetGenerateMemberProperty(true, oCommandLine);
                    }
                }
    
                DesignerSerializationManager castedMgr = manager as DesignerSerializationManager;
    
                // Remove errors arising from unknown method CMDLINE_AddStandardFlagDef...
                castedMgr.Errors.OfType<CodeDomSerializerException>().Where(ex => ex.Message.Contains(CMDLINE_AddStandardFlagDef)).ToList().ForEach(e => castedMgr.Errors.Remove(e));
    
                var unassignedMethodInvokeExpressions = statements.OfType<CodeExpressionStatement>().Where(s => s.Expression is CodeMethodInvokeExpression).Select(s => (CodeMethodInvokeExpression)s.Expression);
    
                var stdFlagInvokations      = unassignedMethodInvokeExpressions.Where(exp => exp.Method.MethodName == CMDLINE_AddStandardFlagDef).ToList();
    
                stdFlagInvokations.ForEach(s =>
                {
                    const int NUM_METHOD_ARGS = 9;
    
                    object[] langParams = s.Parameters.Cast<CodeExpression>().Select(exp => DeserializeExpression(manager, null, exp)).ToArray();
    
                    if(langParams.Length != NUM_METHOD_ARGS)
                        castedMgr.Errors.Add(new CodeDomSerializerException($"Cannot call {oCommandLine.GetType().Name}.{CMDLINE_AddStandardFlagDef} because the number of deserialized parameters is {langParams.Length} but must be {NUM_METHOD_ARGS}.", manager));
                    else
                    {
                        oCommandLine.AddStandardFlagDef((Type)langParams[0],
                                                        (string)langParams[1],
                                                        (string)langParams[2],
                                                        (string)langParams[3],
                                                        Convert.ToUInt16(langParams[4]),
                                                        langParams[5] == null ? (ushort?)null : (ushort?)Convert.ToUInt16(langParams[5]),
                                                        Convert.ToUInt16(langParams[6]),
                                                        langParams[7] == null ? (ushort?)null : (ushort?)Convert.ToUInt16(langParams[7]),
                                                        (char[])langParams[8]);
                    }
                });
    
    
                return oCommandLine;
            }
    
            public override object Serialize(IDesignerSerializationManager manager, object value)
            {
    
                /* Associate the component with the serializer in the same manner as with Deserialize */
                CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
                    GetSerializer(typeof(CommandLine).BaseType, typeof(CodeDomSerializer));
    
                object codeObject = baseClassSerializer.Serialize(manager, value);
    
                CommandLine cl = value as CommandLine;
    
                if(cl == null)
                    return codeObject;  // Return whatever was serialized
    
                string varCmdLineName = manager.GetName(value);
    
                if(codeObject is CodeStatementCollection)
                {
                    CodeStatementCollection statements = (CodeStatementCollection)codeObject;
    
                    var eStatements = statements.OfType<CodeStatement>();
                    var assigns = eStatements.OfType<CodeAssignStatement>().Where(cas => cas.Left is CodePropertyReferenceExpression).Select(cas => ((CodePropertyReferenceExpression)cas.Left).PropertyName).ToArray();
    
                    bool createdField = SetCommandLineDefinitionDeclaration(manager, value, statements);
    
                    CodeExpression varCmdLine;
    
                    if(createdField)
                    {
                        varCmdLine = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), varCmdLineName);
    
                        //
                        // Replace property references to prepend with 'this'.
                        //
                        statements.OfType<CodeAssignStatement>()
                                  .Where(cas =>
                                    {
                                        // Only return assign statements for this DataPullBase object (i.e. with name == varDataPullName)
    
                                        CodePropertyReferenceExpression propExp = cas.Left as CodePropertyReferenceExpression;
    
                                        if (propExp == null)
                                            return false;
    
                                        CodeVariableReferenceExpression varCmdLineExp = propExp.TargetObject as CodeVariableReferenceExpression;
    
                                        if (varCmdLineExp == null)
                                            return false;
    
                                        return varCmdLineExp.VariableName == varCmdLineName;
                                    })
                                    .ToList().ForEach(cas =>
                                    {
                                        CodePropertyReferenceExpression propExp = cas.Left as CodePropertyReferenceExpression;
                                        cas.Left = new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), varCmdLineName), propExp.PropertyName);
                                    });
                    }
                    else
                        varCmdLine = new CodeVariableReferenceExpression(varCmdLineName);
    
    
                    CodeTypeDeclaration typeDecl = manager.Context[typeof(CodeTypeDeclaration)] as CodeTypeDeclaration;
    
                    List<CodeMemberField> listFlagNamesDecl = new List<CodeMemberField>(), listFlagDescDecl = new List<CodeMemberField>(), listFlagHandleDecl = new List<CodeMemberField>();
    
                    //
                    // Process Standard Flag Definitions
                    //
                    if(cl.StandardFlagDefinitions.Length > 0)
                    {
                        statements.Add(new CodeCommentStatement(string.Empty));
                        statements.Add(new CodeCommentStatement("Adding standard flag definitions"));
                        statements.Add(new CodeCommentStatement(string.Empty));
                    }
                    foreach (CommandLineFlagDef flagDef in cl.StandardFlagDefinitions)
                    {
                        string fldName = $"_flag_{flagDef.FlagName.OnlyAlphaNumeric(true).Replace(' ', '_')}";
    
                        CodeMemberField fldNameDecl = new CodeMemberField(typeof(string), fldName); // { Attributes = MemberAttributes.Private | MemberAttributes.Const,*/ InitExpression = new CodePrimitiveExpression(flagDef.FlagName) };
    
                        CodeMethodInvokeExpression method = new CodeMethodInvokeExpression(varCmdLine,
                                                                                           CMDLINE_AddStandardFlagDef,
                                                                                           new CodeTypeOfExpression(flagDef.FlagType),
                                                                                           new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fldName),
                                                                                           new CodePrimitiveExpression(flagDef.FlagDescription),
                                                                                           new CodePrimitiveExpression(flagDef.PrototypeValue),
                                                                                           new CodePrimitiveExpression(flagDef.MinRequiredFlagInstances),
                                                                                           new CodePrimitiveExpression(flagDef.MaxAllowedFlagInstances),
                                                                                           new CodePrimitiveExpression(flagDef.MinRequiredFlagValues),
                                                                                           new CodePrimitiveExpression(flagDef.MaxAllowedFlagValues),
                                                                                           new CodeArrayCreateExpression(new CodeTypeReference(typeof(char[])), flagDef.FlagValueDelimiters.Select(delim => new CodePrimitiveExpression(delim)).ToArray()));
    
                        CodeExpressionStatement flagAdd = new CodeExpressionStatement(method);
    
                        CodeAssignStatement assignFieldName = new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fldName), new CodePrimitiveExpression(flagDef.FlagName));
    
                        typeDecl?.Members.Add(fldNameDecl);
                        statements.Add(assignFieldName);
                        statements.Add(flagAdd);
                    }
                }
                return codeObject;
            }
    

    Thank you,

    Tony

    Friday, August 2, 2019 5:01 PM
  • Hi TonyArch, 

    Thanks for your feedback.

    Could you describe clearly about you problem?

    Besides, what’s type of project? We need to know the type of your project first.

    Thank you for your understanding.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, August 6, 2019 9:45 AM
    Moderator
  • Hi Xingyu,

    I am not really sure I know what you need?  So let me just recap my original post.

    I am using Visual Studio 2015 on Windows 7 and developing a couple System.ComponentModel.Components to allow any user to configure application logistics and to provide some uniform behavior.  One component is a CommandLine component which defines flags to be used by the application along with usage guidelines.  The CommandLine can be defined in code or via a designer.  As you can imagine, I use custom designers, editors, converters and serializers.  My problem was that using the designer that prior flag incarnations persist i.e. in the designer I create a flag called -myOrig and serialize the command line to a .Designer file and all looks good.  Then I change the flag name to -myChanged and when I serialize both -myOrig and -myChanged are defined as fields but only -myChanged is used within the .Designer file code.  In the debugger I looked everywhere I would think to look and can find no reference to -myOrig so I am perplexed why it is being serialized as a field definition.  Hence my question :)

    Does this help at all?

    Tuesday, August 6, 2019 9:47 PM
  • The other issue is that I wanted to (preferably) expose the flag name fields in the .Designer file as public const or (secondarily) as auto-generated read-only wrapper properties in the .Designer file.
    Wednesday, August 7, 2019 12:41 AM
  • Hi TonyArch,

    Thanks for your update.

    I am trying to make a test based on your code on my side.

    There might be some time delay. Appreciate your patience.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, August 9, 2019 8:21 AM
    Moderator
  • Hi Xingyu ,

    I was out on leave for several weeks.  Just wondering if you have any further insight on this?

    Thursday, September 26, 2019 9:18 PM