.NET Framework Developer Center > .NET Development Forums > Windows Workflow Foundation > Bound Dynamic properties not retained after save - Using Vihang Dalal's Designer Rehosting
Ask a questionAsk a question
 

AnswerBound Dynamic properties not retained after save - Using Vihang Dalal's Designer Rehosting

  • Tuesday, September 19, 2006 8:44 PMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I am using Designer Rehosting code posted by Vihang Dalal.
    I am also using DynamicPropertiesActivity from Ghenadie's blog.

    I create a workflow with DynamicPropertyActivity as one of the activities.
    Added 'strTest' to DynamicProperties collection.
    In order to be able to use this attribute in the rest of the workflow to bing to other activities, I believe I have to bind 'strTest' to a new member. So created a new Property member say dynProp_strTest. I can now use dynProp_strTest to bind to other activities. So far so good.
    The issue comes up when I try to save this workflow and then reopen it again in Designer.

    I can no longer see the new member 'dynProp_strTest' that I created. I understand it is getting lost during Save, but do not exactly know how and where.
    Here is the Save code (As far as I remember I am using the same code posted by Vihang and have not made any modifications to this method).

    Highly appreciate any pointers to help resolve the issue.

            public String Save(string filePath)
            {
                if (this.loader != null)
                {
                    if (filePath != null && filePath != string.Empty)
                        this.loader.Xoml = filePath;
                    this.loader.Flush();
                }

                // Referesh the code compile unit every time the file is saved
                TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));
                typeProvider.RemoveCodeCompileUnit(this.loader.XamlCodeCompileUnit);
                this.loader.XamlCodeCompileUnit = new CodeCompileUnit();
                this.loader.XamlCodeCompileUnit.Namespaces.Add(Helpers.GenerateCodeFromXomlDocument(Helpers.GetRootActivity(filePath != null ? filePath : this.loader.Xoml), this, ref this.nameSpace, ref this.typeName));
                typeProvider.AddCodeCompileUnit(this.loader.XamlCodeCompileUnit);
                // Returning the file name
                if (filePath != null && filePath != string.Empty)
                    return filePath;
                else
                    return this.loader.Xoml;

            }


Answers

  • Friday, November 17, 2006 5:53 AMTom LakeMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    The underlying problem has nothing to do with Ghenadie's DynamicPropertiesActivity.  It is because the Designer Rehosting sample does not use the previously saved .cs file when the workflow is reloaded.  This is because there are no .NET library functions to parse the .cs file and turning it into a CodeCompileUnit, and it would be way to much work for a sample.  The last four lines for LoadWorkflow create the default empty class when any workflow is loaded:

     

    // Add the code compile unit for the xaml file

    TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));

    this.loader.XamlCodeCompileUnit = new CodeCompileUnit();

    this.loader.XamlCodeCompileUnit.Namespaces.Add(Helpers.GenerateCodeFromXomlDocument(Helpers.GetRootActivity(xoml), this, ref this.nameSpace, ref this.typeName));

    typeProvider.AddCodeCompileUnit(this.loader.XamlCodeCompileUnit);

     

  • Friday, December 01, 2006 6:30 AMTom LakeMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Two options you could try are writing a CSharp parser that will read the .cs file in and give back the CodeCompileUnit or have logic that would parse the xoml file to figure out which variable / properties had been added and re-add them.  There is no easy solution for this.  You should be able to do the following:

     

    // Add the code compile unit for the xaml file

    string codeFilePath = Path.ChangeExtension(xoml, "cs");

    CodeCompileUnit codeCompileUnit = null;

    TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));

     

    if (File.Exists(codeFilePath))

    {

     

        CSharpCodeProvider csharpProvider = new CSharpCodeProvider();

        codeCompileUnit = csharpProvider.Parse(File.OpenText(codeFilePath));

     

    }

    else

    {

        codeCompileUnit = new CodeCompileUnit();

        codeCompileUnit.Namespaces.Add(Helpers.GenerateCodeFromXomlDocument(Helpers.GetRootActivity(xoml), this, ref this.nameSpace, ref this.typeName));

    }

     

    this.loader.XamlCodeCompileUnit = codeCompileUnit;

    typeProvider.AddCodeCompileUnit(this.loader.XamlCodeCompileUnit);

     

    But the Parse method is not implemented in the CSharpCodeProvider.

  • Friday, January 05, 2007 8:25 AMTom LakeMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    After looking at the code it looks like the parser you are using is not doing its job correctly.  It seems to be parsing variables correctly, but not properties.

All Replies

  • Tuesday, October 17, 2006 5:12 AMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I have been looking more into this and I now think the issue is with the way GenerateCodeFromCompileUnit in PerformFlush method of Loader.cs is implemented.
    But I am still unable to figure out the exact issue.

    When the workflow is open and I re-bind the dynamic properties to new members, the .cs file corresponding to the workflow gets correctly updated with the created new dependency property members. But when I close the file and open it again, the PerformFlush method basically wipes out the newly added dependency properties corresponding to the dynamic property.

    Has anyone got the dynamic properties and the designer to work together successfully.
    Really appreciate any pointers in the direction of resolving this issue.

    Please let me know if there is any other information that you might require if I was not clear in description of the problem.

    Thanks a lot in advance.
  • Thursday, October 26, 2006 4:43 AMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Any clues please!!
  • Wednesday, November 15, 2006 5:43 AMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I have not recieved any replies on this so far.
    Has no-one faced this problem yet? OR Is the problem description unclear?

    Highly appreciate if I can recieve any responses or further queries.
    Thanks a lot in advance.
  • Friday, November 17, 2006 5:53 AMTom LakeMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    The underlying problem has nothing to do with Ghenadie's DynamicPropertiesActivity.  It is because the Designer Rehosting sample does not use the previously saved .cs file when the workflow is reloaded.  This is because there are no .NET library functions to parse the .cs file and turning it into a CodeCompileUnit, and it would be way to much work for a sample.  The last four lines for LoadWorkflow create the default empty class when any workflow is loaded:

     

    // Add the code compile unit for the xaml file

    TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));

    this.loader.XamlCodeCompileUnit = new CodeCompileUnit();

    this.loader.XamlCodeCompileUnit.Namespaces.Add(Helpers.GenerateCodeFromXomlDocument(Helpers.GetRootActivity(xoml), this, ref this.nameSpace, ref this.typeName));

    typeProvider.AddCodeCompileUnit(this.loader.XamlCodeCompileUnit);

     

  • Friday, November 17, 2006 3:46 PMDudley Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    This is slightly alarming - don't you think?

    It sounds like the only way to load your .cs file back in to a program hosting the workflow design component would be to build your own c sharp parser!

    I'm just wondering how useful the workflow designer component is going to be if it has a fundamental flaw like this??

     

     

     

  • Saturday, November 18, 2006 5:12 AMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Is there anyway to circumvent this problem in Designer Hosting app?
    Will be grateful for any suggestions to overcome this problem.

    Thanks in advance.
  • Friday, December 01, 2006 6:30 AMTom LakeMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Two options you could try are writing a CSharp parser that will read the .cs file in and give back the CodeCompileUnit or have logic that would parse the xoml file to figure out which variable / properties had been added and re-add them.  There is no easy solution for this.  You should be able to do the following:

     

    // Add the code compile unit for the xaml file

    string codeFilePath = Path.ChangeExtension(xoml, "cs");

    CodeCompileUnit codeCompileUnit = null;

    TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));

     

    if (File.Exists(codeFilePath))

    {

     

        CSharpCodeProvider csharpProvider = new CSharpCodeProvider();

        codeCompileUnit = csharpProvider.Parse(File.OpenText(codeFilePath));

     

    }

    else

    {

        codeCompileUnit = new CodeCompileUnit();

        codeCompileUnit.Namespaces.Add(Helpers.GenerateCodeFromXomlDocument(Helpers.GetRootActivity(xoml), this, ref this.nameSpace, ref this.typeName));

    }

     

    this.loader.XamlCodeCompileUnit = codeCompileUnit;

    typeProvider.AddCodeCompileUnit(this.loader.XamlCodeCompileUnit);

     

    But the Parse method is not implemented in the CSharpCodeProvider.

  • Friday, January 05, 2007 5:05 AMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Based on your suggestion above, I have implemented the Parse method which will return the codeCompileUnit and replaced the last four lines of code in LoadWorkflow with the lines suggested by you.
    But I wonder if this is sufficient.
    In WorkflowLoader constructor the codeBesideccu variable is being built with hardcoded values and this is what is used in PerformFlush method in the line
                generator.GenerateCodeFromCompileUnit(this.CodeBesideCCU, writer, options);
    Now this will flush out whatever was there in .cs file and fill it in with only the codeBesideccu content which is hardcoded and populated in the workflowLoader constructor.
    This I suspect removes all contents of the .cs file and retains just the skeleton. So I am back to square one.

    So the code snippet that you suggested with Parse implemented alone may not be a solution to the problem I am facing. Could you please help me proceed further on this.

    Thanks a ton in advance.
  • Friday, January 05, 2007 5:33 AMTom LakeMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Please post or send me the code your are using.  this.CodeBesideCCU should be the code compile unit that you put into the loader when you opened the workflow.
  • Friday, January 05, 2007 5:55 AMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks for the quick response.
    I have just mailed you the relevant files.
    Please let me know if you would need any other information or have any more questions regarding my approach.

    Thanks a ton.
  • Friday, January 05, 2007 8:25 AMTom LakeMSFTUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    After looking at the code it looks like the parser you are using is not doing its job correctly.  It seems to be parsing variables correctly, but not properties.
  • Friday, January 05, 2007 5:20 PMNMM Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I faced the same problem.. pls when you reach to a solution can you post it step-by-step to solve this problem... thanks
  • Wednesday, January 10, 2007 12:52 PMEdmundas Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Regarding CodeCompileUnit issue:

    I guess there is one more option besides the two suggested above on how to create CodeCompileUnit from *.cs (CSharp parser) or *.xoml file. What if you modify Designer Rehosting sample to save not only *.cs file, but also save binary serialized CodeCompileUnit as well? In that case when loading *.cs file, you would also be able to use appropriate deserialized CodeCompileUnit.

    Edmundas

  • Thursday, January 11, 2007 5:53 AMBirth of presence Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    SolveIt!! I am facing the same problem. I hope you would have good intuition into the problem now.Please tell me how did you change the sample to keep the existing code intact. Please help.
  • Thursday, January 11, 2007 6:06 AMSolveIt Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Sounds like a good idea to serialize CodeCompileUnit itself!! Let me try it out.
  • Monday, November 05, 2007 9:37 PMDaveAtDotNetCodeSlingersDotCom Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    SolveIt,

     

    Can you please post as to what has come from your testing and any code that solves this as well?

     

    Anyone else solve this issue?

     

    Thanks,

    Dave

     

  • Wednesday, January 16, 2008 12:50 AMJonathon.Bradley Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Bump.

    I'm facing a similar problem. Has there been any developments?

    The main issue I'm having with the Designer is it ignores the workflows .cs file. In fact, it will auto generates a basic .cs file when loading the workflow.

    thanks for your time and help.
  • Wednesday, February 06, 2008 2:46 PMmuratdp Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Dear sir,

    -firstof all sory my english.-

     

    I have same stiuation in rehosting example.I try to find a solution in this way that you can see below;

    target idea : we may not parse a code (or maybe just me) but we can compile it and get assembly and type.

    1) in

    public void LoadWorkflow(string xoml) method implementation replace

     

    TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));

    this.loader.XamlCodeCompileUnit = new CodeCompileUnit();

    this.loader.XamlCodeCompileUnit.Namespaces.Add(Helpers.GenerateCodeFromXomlDocument(Helpers.GetRootActivity(xoml), this, ref this.nameSpace, ref this.typeName));

    typeProvider.AddCodeCompileUnit(this.loader.XamlCodeCompileUnit);

     

    with this code

     

    bool fileExist = false; ;

    string destinationFilePath = Path.GetDirectoryName(xoml) + "\\temp.cs";

    string codeFilePath = Path.ChangeExtension(xoml, "cs");

    if (File.Exists(codeFilePath))

    {

    fileExist = true;

    File.Copy(codeFilePath, destinationFilePath, true);

    }


    TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));

    this.loader.XamlCodeCompileUnit = new CodeCompileUnit();

    this.loader.XamlCodeCompileUnit.Namespaces.Add(Helpers.GenerateCodeFromXomlDocument(Helpers.GetRootActivity(xoml), this, ref this.nameSpace, ref this.typeName));

    typeProvider.AddCodeCompileUnit(this.loader.XamlCodeCompileUnit);

    if (fileExist)

    {

    ReGenerateWorkflowCode(destinationFilePath);

    }

     

    2)Add this method in workflowdesigner.cs file (

    "MyActivityLibrary.dll" just for me please remove it.

    )

     

    private void ReGenerateWorkflowCode(string codeFilePath)

    {

    IMemberCreationService memberCreationService = GetService(typeof(IMemberCreationService)) as IMemberCreationService;

    if (memberCreationService == null)

    {

    throw new InvalidOperationException("IMemberCreationService is null.");

    }

    CSharpCodeProvider csharpProvider = new CSharpCodeProvider();

    CodeCompileUnit codeCompileUnit = new CodeCompileUnit();

    // Compile the assembly with the appropriate references

    string[] assemblyReferences = new string[] { "System.dll" ,

    "MyActivityLibrary.dll",

    @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Workflow.Activities.dll",

    @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Workflow.ComponentModel.dll",

    @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll",

    @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Workflow.Runtime.dll"

    };

    CompilerParameters param = new CompilerParameters(assemblyReferences);

    param.MainClass = this.className;

    param.GenerateExecutable = false;

    param.GenerateInMemory = false;

    param.TreatWarningsAsErrors = false;

    param.WarningLevel = 4;

    TempFileCollection tempFileCollection = new TempFileCollection(".", true);

    CompilerResults results = new CompilerResults(tempFileCollection);

    results = csharpProvider.CompileAssemblyFromFile(param, new string[] { codeFilePath });

    foreach (CompilerError error in results.Errors)

    {

    Trace.WriteLine(error.ToString());

    }

    Assembly assembly = results.CompiledAssembly;

    string className = "foo." + this.className;

    Type workflowType = assembly.GetType(className);

    PropertyInfo[] propertyInfo = workflowType.GetProperties();

    foreach (PropertyInfo pi in propertyInfo)

    {

    if (pi.DeclaringType != workflowType)

    {

    continue;

    }


    List<CodeAttributeDeclaration> arrayList = new List<CodeAttributeDeclaration>();

    object[] attList = pi.GetCustomAttributes(false);

    CodeAttributeDeclaration cad = null;

    foreach (Attribute attr in attList)

    {

    if (attr is CategoryAttribute)

    {

    cad = new CodeAttributeDeclaration(new CodeTypeReference(typeof(CategoryAttribute)));

    cad.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(((CategoryAttribute)attr).Category)));

    arrayList.Add(cad);

    cad = new CodeAttributeDeclaration(new CodeTypeReference(typeof(BrowsableAttribute)));

    cad.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(true)));

    arrayList.Add(cad);

    cad = new CodeAttributeDeclaration(new CodeTypeReference(typeof(DesignerSerializationVisibilityAttribute)));

    cad.Arguments.Add(new CodeAttributeArgument(new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(typeof(DesignerSerializationVisibility)), "Visible")));

    arrayList.Add(cad);

    break;

    }

    }

    if (arrayList.Count == 0)

    {

    continue;

    }

    string propertyName = pi.Name;

    Type propertyType = pi.PropertyType;

    bool emitDependencyProperty = true;

    bool isMetaProperty = false;

    bool isAttached = false;

    Type ownerType = null;

    bool isReadOnly = false;

    ((MemberCreationService)memberCreationService).CreateProperty(className, propertyName, propertyType, arrayList, emitDependencyProperty, isMetaProperty, isAttached, ownerType, isReadOnly);

    }

    }

     

    3)

    MemberCreationService.cs file add this overloading methods.

     

    public void CreateProperty(string className, string propertyName, Type propertyType, List<CodeAttributeDeclaration> codeAttributeDeclarationList, bool emitDependencyProperty, bool isMetaProperty, bool isAttached, Type ownerType, bool isReadOnly)

    {

    if (string.IsNullOrEmpty(className))

    throw new ArgumentNullException("className");

    if (string.IsNullOrEmpty(propertyName))

    throw new ArgumentNullException("propertyName");

    if (propertyType == null)

    throw new ArgumentNullException("propertyType");

    if (!this.CodeProvider.IsValidIdentifier(propertyName))

    throw new ArgumentException("Invalid Identifier");

    if (!this.DoesPropertyExist(className, propertyName, propertyType))

    {

    // create property

    CodeMemberProperty property = new CodeMemberProperty();

    property.Name = propertyName;

    property.Type = GetCodeTypeReference(className, propertyType);

    property.Attributes = MemberAttributes.Public | MemberAttributes.Final;

    // add property attributes

    if (codeAttributeDeclarationList != null)

    {

    foreach (CodeAttributeDeclaration codeAttributeDeclaration in codeAttributeDeclarationList)

    {

    property.CustomAttributes.Add(codeAttributeDeclaration);

    }

    }

    // Create private field to hold the property's data

    IDesignerHost host = this.ServiceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;

    if (host == null)

    throw new InvalidOperationException(typeof(IDesignerHost).FullName);

    ITypeProvider typeProvider = this.ServiceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;

    if (typeProvider == null)

    throw new InvalidOperationException(typeof(ITypeProvider).FullName);

    string fieldName = null;

    if (emitDependencyProperty)

    {

    fieldName = propertyName + "Property";

    property.UserData["_vsDependencyPropertyFieldKey"] = fieldName;

    if (!isAttached)

    CreateStaticFieldForDependencyProperty(className, propertyName, propertyType, fieldName, isMetaProperty, false);

    }

    else

    {

    bool existingField = false;

    //We recreate the field everytime, this is done for the dynamic properties

    fieldName = GeneratePropertyAssociatedFieldName(className, propertyName, propertyType, out existingField);

    if (!existingField)

    CreateField(className, fieldName, propertyType, null, MemberAttributes.Private, null, true);

    }

    // Add getter and setter logic to retrieve and assign the value to the new private field

    if (emitDependencyProperty)

    {

    CodeFieldReferenceExpression fieldRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(isAttached ? ownerType.FullName : className), fieldName);

    property.HasGet = true;

    CodeTypeReference typeRef = new CodeTypeReference(propertyType);

    property.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(typeRef, new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), "GetValue", fieldRef))));

    if (!isReadOnly)

    {

    property.HasSet = true;

    property.SetStatements.Add(new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), "SetValue", fieldRef, new CodeSnippetExpression("value")));

    }

    }

    else

    {

    property.HasGet = true;

    property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));

    if (!isReadOnly)

    {

    property.HasSet = true;

    CodeExpression ifNOTDesignModeExpression = new CodeBinaryOperatorExpression(new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DesignMode"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));

    property.SetStatements.Add(new CodeConditionStatement(ifNOTDesignModeExpression, new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(InvalidOperationException), new CodeExpression[] { }))));

    property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodeSnippetExpression("value")));

    }

    }

    string nsName = null;

    Helpers.GetNamespaceAndClassName(className, out nsName, out className);

    CodeTypeDeclaration typeDeclaration = GetCodeTypeDeclFromCodeCompileUnit(nsName, className);

    int index = 0;

    foreach (CodeTypeMember member in typeDeclaration.Members)

    {

    if (member is CodeMemberProperty)

    index++;

    else

    break;

    }

    typeDeclaration.Members.Insert(index, property);

    ((TypeProvider)typeProvider).RefreshCodeCompileUnit(this.loader.CodeBesideCCU, new EventHandler(RefreshCCU));

    }

    }

     

    public void CreateProperty(string className, string propertyName, Type propertyType, List<CodeAttributeDeclaration> codeAttributeDeclarationList, bool emitDependencyProperty, bool isMetaProperty, bool isAttached, Type ownerType, bool isReadOnly)

    {

    if (string.IsNullOrEmpty(className))

    throw new ArgumentNullException("className");

    if (string.IsNullOrEmpty(propertyName))

    throw new ArgumentNullException("propertyName");

    if (propertyType == null)

    throw new ArgumentNullException("propertyType");

    if (!this.CodeProvider.IsValidIdentifier(propertyName))

    throw new ArgumentException("Invalid Identifier");

    if (!this.DoesPropertyExist(className, propertyName, propertyType))

    {

    // create property

    CodeMemberProperty property = new CodeMemberProperty();

    property.Name = propertyName;

    property.Type = GetCodeTypeReference(className, propertyType);

    property.Attributes = MemberAttributes.Public | MemberAttributes.Final;

    // add property attributes

    if (codeAttributeDeclarationList != null)

    {

    foreach (CodeAttributeDeclaration codeAttributeDeclaration in codeAttributeDeclarationList)

    {

    property.CustomAttributes.Add(codeAttributeDeclaration);

    }

    }

    // Create private field to hold the property's data

    IDesignerHost host = this.ServiceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;

    if (host == null)

    throw new InvalidOperationException(typeof(IDesignerHost).FullName);

    ITypeProvider typeProvider = this.ServiceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;

    if (typeProvider == null)

    throw new InvalidOperationException(typeof(ITypeProvider).FullName);

    string fieldName = null;

    if (emitDependencyProperty)

    {

    fieldName = propertyName + "Property";

    property.UserData["_vsDependencyPropertyFieldKey"] = fieldName;

    if (!isAttached)

    CreateStaticFieldForDependencyProperty(className, propertyName, propertyType, fieldName, isMetaProperty, false);

    }

    else

    {

    bool existingField = false;

    //We recreate the field everytime, this is done for the dynamic properties

    fieldName = GeneratePropertyAssociatedFieldName(className, propertyName, propertyType, out existingField);

    if (!existingField)

    CreateField(className, fieldName, propertyType, null, MemberAttributes.Private, null, true);

    }

    // Add getter and setter logic to retrieve and assign the value to the new private field

    if (emitDependencyProperty)

    {

    CodeFieldReferenceExpression fieldRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(isAttached ? ownerType.FullName : className), fieldName);

    property.HasGet = true;

    CodeTypeReference typeRef = new CodeTypeReference(propertyType);

    property.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(typeRef, new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), "GetValue", fieldRef))));

    if (!isReadOnly)

    {

    property.HasSet = true;

    property.SetStatements.Add(new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), "SetValue", fieldRef, new CodeSnippetExpression("value")));

    }

    }

    else

    {

    property.HasGet = true;

    property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));

    if (!isReadOnly)

    {

    property.HasSet = true;

    CodeExpression ifNOTDesignModeExpression = new CodeBinaryOperatorExpression(new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DesignMode"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));

    property.SetStatements.Add(new CodeConditionStatement(ifNOTDesignModeExpression, new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(InvalidOperationException), new CodeExpression[] { }))));

    property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodeSnippetExpression("value")));

    }

    }

    string nsName = null;

    Helpers.GetNamespaceAndClassName(className, out nsName, out className);

    CodeTypeDeclaration typeDeclaration = GetCodeTypeDeclFromCodeCompileUnit(nsName, className);

    int index = 0;

    foreach (CodeTypeMember member in typeDeclaration.Members)

    {

    if (member is CodeMemberProperty)

    index++;

    else

    break;

    }

    typeDeclaration.Members.Insert(index, property);

    ((TypeProvider)typeProvider).RefreshCodeCompileUnit(this.loader.CodeBesideCCU, new EventHandler(RefreshCCU));

    }

    }

    After that you can push the save button.code beside file will not be emty.

    This could be not vaild solution but i developed and i want to share with you.

     

    murat pekcan

    turkey


     

  • Monday, February 18, 2008 6:58 AMCraig3 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Did anyone come up with an example of how to load in properties, fields and events generated dynamically?  I'm a bit confused why we need to have two code compile units, and when to use them.  Appreciate any help.

     

    Craig

  • Tuesday, June 03, 2008 7:28 PMAllan-Nielsen Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    did you guys solve any of your issues here ?

     

    regards Allan

     

  • Monday, September 08, 2008 4:14 PMjuanchosaravia Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    did you guys solve any of your issues here ? I have the same problem!!
  • Saturday, January 24, 2009 12:31 PMHimal Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hello, I am facing the same problem. I bound property and it works fine until i save and re open it. when i reopen the same workflow, that property get losts. i am saving the workflow files(cs, rules, xoml, layout) in the database.

    Please provide me the solution if any one have it.

    Thanks in Advance.

    Himal


    Himal
  • Wednesday, April 01, 2009 10:14 AMDenis Pankratov Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hello, Himal!

    I want look on solution.
    Can you send me it?


    SmD
  • Monday, April 20, 2009 8:53 AMrh2 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi SolveIt

    I'm getting this problem - really annoying !! did you ever find a good solution? If so please can you post your parser,

    Thanks a lot
  • Monday, September 21, 2009 6:39 AMMasus_84 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Proposed AnswerHas Code
    Hi everyone. I know this post is quite old, but since it seems no solution has been posted yet and this post is one of the first post you will find when you search for the problem I thought that I could give it a try to contribute something:)

    I managed to get the properties to load after save -> restart -> load. 

    My solution is very basic and works as follows (inspired by many post around this subject):
    1. When the workflow is saved, serialize the CodeBesideCCU as a binary file.
    2. When workflow is loaded, deserialize the binary representation of the CodeBesideCCU and replace the old one with it.
    The serializiation code (credits to unknown programmer):

    private byte[] SerializeCCU(CodeCompileUnit codeCompileUnit1)
     {
         MemoryStream ms = new MemoryStream();
         BinaryFormatter formatter = new BinaryFormatter();
         formatter.Serialize(ms, codeCompileUnit1);
         ms.Seek(0, SeekOrigin.Begin);
         return ms.ToArray();
     }
    
    
    private CodeCompileUnit DeserializeCCU(byte[] bytes)
    {
         MemoryStream ms = new MemoryStream();
         ms.Write(bytes, 0, bytes.Length);
         ms.Position = 0;
         BinaryFormatter formatter = new BinaryFormatter();
         return formatter.Deserialize(ms) as CodeCompileUnit;
    }
    
    How to load the serialized CCU (in the LoadWorkflow(String xoml) method in WorkflowDesignerControl.cs):

    // Add the code compile unit for the code beside file
    string codeFilePath = Path.ChangeExtension(xoml, "bin");
    TypeProvider typeProvider = (TypeProvider)GetService(typeof(ITypeProvider));
    if (File.Exists(codeFilePath))
    {
       using (FileStream fs = File.Open(codeFilePath, FileMode.Open))
       {
           long length = fs.Length;
           BinaryReader br = new BinaryReader(fs);
           byte[] result = br.ReadBytes((int)length);
           CodeCompileUnit codeBesideCompileUnit = this.DeserializeCCU(result);
           //Remove old CodeBesideCCU
           typeProvider.RemoveCodeCompileUnit(this.loader.CodeBesideCCU);
           this.loader.CodeBesideCCU = codeBesideCompileUnit;
           //Add the new deserialized one.
           typeProvider.AddCodeCompileUnit(this.loader.CodeBesideCCU);
       }
    }
    
    To serialize the CCU (in the Save(String path) method in WorkflowDesignerControl.cs):

    // Referesh the code compile unit every time the file is saved
    byte[] compileUnitAsBytes = this.SerializeCCU(this.loader.CodeBesideCCU);
    File.WriteAllBytes(Path.ChangeExtension(this.loader.Xoml, "bin"), compileUnitAsBytes);
    

    As usual, this code come without any warranty:)

    Hope it helps!


    • Proposed As Answer byVSFustrated Thursday, October 15, 2009 5:34 PM
    •  
  • Tuesday, October 27, 2009 1:37 PMMasus_84 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    I ran into problems myself with my "solution" regarding serializing the CodeBesideCCU. It exist a much more elegant solution and that is to use a .cs parser. I managed to found one called NRefactor, and is available for free. It is part of the IDE SharpDevelop.

    The Parser is not available as a seperate download but you can get it from the SharpDevelop source:

    You need to add the dll ICSharpCode.NRefactory.dll to your project.

    I used the following code to parse the .cs file into a CodeCompileUnit:

    WorkflowLoader loader = new WorkflowLoader();
    loader.Xoml = xoml;
    string codeFilePath = Path.ChangeExtension(xoml, "cs");
    CodeCompileUnit codeCompileUnit = null;
    if (File.Exists(codeFilePath))
    {
        IParser parser;
        parser = ParserFactory.CreateParser(codeFilePath);
        if (parser != null)
        {
            parser.Parse();
            ICSharpCode.NRefactory.Visitors.CodeDomVisitor visit = new ICSharpCode.NRefactory.Visitors.CodeDomVisitor();
            CodeNamespace globalNamespace = (CodeNamespace)visit.VisitCompilationUnit(parser.CompilationUnit, null);
            visit.codeCompileUnit.Namespaces.Remove(globalNamespace);
            visit.codeCompileUnit.Namespaces[0].Types[0].IsPartial = true;
    
            codeCompileUnit = visit.codeCompileUnit;
            parser.Dispose();
            loader.CodeBesideCCU = codeCompileUnit;
        }
    }
    
    
    Hope it helps..It made things alot easier for me:)