Hi there!
I'm writing my own C# component to be used with the Windows Forms Designer.
This component has a DesignerSerializer attached.
Within my CodeDomSerializer I would like to generate additional attributes
that get noted infront of some form controls. Like this:
[My.ActionSourceAttribute("APP17", "New.Action", "")]
private System.Windows.Forms.Button button1;
I really could manage all that to get the attribute generated at the right
place.
My problem is that after inserting the attribute by using DTE, it's no
longer possible to add new controls in the Designer.
To be more precise: One still can add a control using the Designer but no
code is generated for it. If I close the Designer window and re-open it
before adding a new control, everything works fine!
Looks like I will have to update the Designer after adding code
programatically.
Any hints or solutions on that?
-Matthias
Here's the code I used to generate the attribute (ActionManager is the
components class name):
private void OnSerializationComplete(object sender, EventArgs e)
{
IDesignerSerializationManager manager = sender as
IDesignerSerializationManager;
// Attribute writing
AttributeSerialize(actionManager);
manager.SerializationComplete -= new
EventHandler(OnSerializationComplete);
}
private void AttributeSerialize(ActionManager actionManager)
{
try
{
// get our IDesignerHost
IDesignerHost host = actionManager.Container as IDesignerHost;
// get the ProjectItem from VS 8 code machine
ProjectItem pi = host.GetService(typeof(ProjectItem)) as
ProjectItem;
// retrieve the CodeModel from the ProjectItem
CodeModel codeModel = pi.ContainingProject.CodeModel;
// find our CodeType
CodeType codeType =
codeModel.CodeTypeFromFullName(host.RootComponentClassName);
// check if we have to set the attribute on the class itself
and if yes, do so
CheckAndSetAttribute(codeType as CodeElement2, actionManager);
// ok, now scan all parts of the class (partial class)
CodeClass2 classElement = (CodeClass2) codeType;
foreach (CodeClass2 partialClass in classElement.Parts)
{
// and now scan all members of the class
foreach (CodeElement2 memberElement in
partialClass.Members)
{
// check if we have to set the attribute on a field
and if yes, do so
CheckAndSetAttribute(memberElement, actionManager);
}
}
}
catch (Exception)
{
// no DesignerHost, CodeModel, or no such CodeType
}
}
private static readonly string AttributeName =
typeof(ActionSourceAttribute).FullName;
private void CheckAndSetAttribute(CodeElement2 element,
ActionManager actionManager)
{
CodeElements attributes = null;
// is the element one of our UI items we support?
if (element is CodeVariable2)
attributes = ((CodeVariable2) element).Attributes;
else if (element is CodeClass2)
attributes = ((CodeClass2) element).Attributes;
else
return;
// check if we have to remove former attributes
foreach (CodeAttribute2 attribute in attributes)
{
// attribute already there?
if (AttributeName.Equals(attribute.Name))
attribute.Delete();
}
// do we need to set the attribute?
string actionKey =
actionManager.GetActionKeyFromName(element.Name);
if (!string.IsNullOrEmpty(actionKey))
{
// build new attribute value
string attributeValue =
string.Format("\"{0}\",\"{1}\",\"{2}\"",
actionManager.Application, actionKey,
actionManager.GetActionTriggerFromName(element.Name));
// add a new attribute
if (element is CodeVariable2)
((CodeVariable2) element).AddAttribute(AttributeName,
attributeValue, 0);
else if (element is CodeClass2)
((CodeClass2) element).AddAttribute(AttributeName,
attributeValue, 0);
}
}
}
mamu - 10 Sep 2005 11:58 GMT
BTW:
I've the same problem when generating any kind of code, like comments etc.
And one can see if you type in a comment in the .Designer.cs file and switch
back to the designer, it gets refreshed. That would be the thing I will have
to do programatically. But how to do this?
-Matthias