是否有可能控制IExtenderProvider如何格式在Windows窗体设计code的输出? [英] Is it possible to control how IExtenderProvider formats the output in the Windows Forms Designer code?

查看:145
本文介绍了是否有可能控制IExtenderProvider如何格式在Windows窗体设计code的输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类实现 IExtenderProvider

下面是关于该接口 HTTP:/ /www.$c$cproject.com/Articles/4683/Getting-to-know-IExtenderProvider

其基本思想是选择在Windows窗体desinger控制,并有一个虚拟财产在myProperty的MyExtender

工具提示不一样的。

这工作正常,并设计code看起来像这样

  this.label1.AutoSize = TRUE;
...
this.myExtender1.SetMyProperty(this.label1myvalue的);
...
this.label1.Name =LABEL1;
this.label1.Text =LABEL1;
 

有仅通过在属性网格一个下拉菜单允许输入资源字符串从一个特定的资源文件。现在我想才达到这

  this.label1.AutoSize = TRUE;
....
this.myExtender1.SetMyProperty(this.label1,
                 My.Namespace.Properties.Resources.MyValue);
...
this.label1.Name =LABEL1;
this.label1.Text =LABEL1;
 

这是我的资源类的引用字符串变量。 我们的想法是,我想从静态类型利润(如果我重新命名的资源,我得到了设计时间错误,而不是运行时错误)。

有没有办法才达到这一点?

解决方案

这一篇文章,题为的弯曲的code一代IExtenderProvider到你将的添范·沃森霍夫可以解决你的问题。

它指出:

  

探索codeDomSerializer 我已经解释我们如何修改code。该Visual Studio设计为我们生成。在一个典型的 IExtenderProvider 设计器生成一个初始化一些SetXXX方法和变量声明...

     

现在,如果我们不满意的每个组件的生成SetXXX方法?问题在于,不是由串行器为ConstantsExtenderProvider而是由串行器的组件生成此code。一个简单的解决此问题的方法是将<一个href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.designerserializationvisibilityattribute.aspx"相对=nofollow> DesignerSerializationVisibilityAttribute 在我们IExtenderProvider getXXX方法为<一个href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.designerserializationvisibility.aspx"相对=nofollow>隐藏。

     

使用那些丑陋的SetXXX方法出的方式,它是由我们做的更好。为此,我们通过实现自定义序列化对我们ConstantsExtenderProvider:

 类ConstantsSerializer&LT; T&GT; :codeDomSerializer
{
公众覆盖对象序列(IDesignerSerializationManager经理,对象值)
{
ConstantsExtenderProvider提供商=价值ConstantsExtenderProvider;

codeDomSerializer baseClassSerializer = manager.GetSerializer(typeof运算(ConstantsExtenderProvider).BaseType的typeof(codeDomSerializer))为codeDomSerializer;
codeStatementCollection陈述= baseClassSerializer.Serialize(经理,价值)为codeStatementCollection;

IDesignerHost的主机=(IDesignerHost的)manager.GetService(typeof运算(IDesignerHost的));
ComponentCollection成分= host.Container.Components;
this.SerializeExtender(经理,供应商,组件,报表);

return语句;
}

私人无效SerializeExtender(IDesignerSerializationManager经理,ConstantsExtenderProvider提供商,ComponentCollection组件,codeStatementCollection语句)
{
的foreach(在组件IComponent的组件)
{
控制控制=组件作为控制;
如果(控制= NULL和放大器;!及(控制,表== NULL))
{
codeMethodInvokeEx pression methodcall =新的codeMethodInvokeEx pression(base.SerializeToEx pression(经理,供应商),SetConstants);
methodcall.Parameters.Add(新的codeFieldReferenceEx pression(新的codeThisReferenceEx pression(),control.Name));

字符串[]常量= provider.GetConstants(控制);
如果(常量!= NULL)
{
StringBuilder的SB =新的StringBuilder();
sb.Append(新的String [] {);

的foreach(常量字符串常量)
{
sb.Append(typeof运算(T).FullName);
sb.Append(。);
sb.Append(常数);
sb.Append(,);
}

sb.Remove(sb.Length  -  2,2);
sb.Append(});

methodcall.Parameters.Add(新的codeSnippetEx pression(sb.ToString()));
}
    其他
{
methodcall.Parameters.Add(新的codePrimitiveEx pression(空));
}

statements.Add(methodcall);
}
}
}
}
 

  

和现在所产生的code是这样的:

  this.constantsExtenderProvider1.SetConstants(this.button1,新的String [] {
    WindowsApplication1.Constants.Operation1,
    WindowsApplication1.Constants.Operation5
});
 

I have a class that implements IExtenderProvider

Here is a great article about that interface http://www.codeproject.com/Articles/4683/Getting-to-know-IExtenderProvider

The basic idea is to select a control in the windows forms desinger and have a "virtual" property MyProperty on MyExtender

The tooltip does the same.

This works as expected and the designer code looks like this

this.label1.AutoSize = true;
...
this.myExtender1.SetMyProperty(this.label1, "MyValue");
...
this.label1.Name = "label1";
this.label1.Text = "label1";

It is only allowed to input resource strings from a specific resource file via a drop down menu in the property grid. Now what I want to achive is this

this.label1.AutoSize = true;
....
this.myExtender1.SetMyProperty(this.label1, 
                 My.Namespace.Properties.Resources.MyValue);
...
this.label1.Name = "label1";
this.label1.Text = "label1";

which is the reference to the string variable in my resource class. The idea is that I want to profit from the static typing (If I rename a resource I get design time errors rather than runtime errors).

Is there a way to achive this?

解决方案

This article titled "Bending the code generation of IExtenderProvider to your will" by Tim Van Wassenhove may solve your problem.

It states:

In Exploring CodeDomSerializer i already explained how we can modify the code that the Visual Studio designer generates for us. With a typical IExtenderProvider the designer generates an initializer, SetXXX methods and a variable declaration...

Now, what if we’re not happy with those generated SetXXX methods on each Component? The problem is that this code is not generated by the serializer for the ConstantsExtenderProvider but by the serializers for the Components. An easy workaround for this problem is to set the DesignerSerializationVisibilityAttribute on the GetXXX method in our IExtenderProvider to Hidden.

With those ugly SetXXX methods out of the way it’s up to us to do it better. We do this by implementing a custom serializer for our ConstantsExtenderProvider:

class ConstantsSerializer<t> : CodeDomSerializer
{
 public override object Serialize(IDesignerSerializationManager manager, object value)
 {
  ConstantsExtenderProvider provider = value as ConstantsExtenderProvider;
 
  CodeDomSerializer baseClassSerializer = manager.GetSerializer(typeof(ConstantsExtenderProvider).BaseType, typeof(CodeDomSerializer)) as CodeDomSerializer;
  CodeStatementCollection statements = baseClassSerializer.Serialize(manager, value) as CodeStatementCollection;
 
  IDesignerHost host = (IDesignerHost)manager.GetService(typeof(IDesignerHost));
  ComponentCollection components = host.Container.Components;
  this.SerializeExtender(manager, provider, components, statements);
 
  return statements;
 }
 
 private void SerializeExtender(IDesignerSerializationManager manager, ConstantsExtenderProvider provider, ComponentCollection components, CodeStatementCollection statements)
 {
  foreach (IComponent component in components)
  {
   Control control = component as Control;
   if (control != null && (control as Form == null))
   {
    CodeMethodInvokeExpression methodcall = new CodeMethodInvokeExpression(base.SerializeToExpression(manager, provider), "SetConstants");
    methodcall.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), control.Name));
 
    string[] constants = provider.GetConstants(control);
    if (constants != null)
    {
     StringBuilder sb = new StringBuilder();
     sb.Append("new string[] { ");
 
     foreach (string constant in constants)
     {
      sb.Append(typeof(T).FullName);
      sb.Append(".");
      sb.Append(constant);
      sb.Append(", ");
     }
 
     sb.Remove(sb.Length - 2, 2);
     sb.Append(" }");
 
     methodcall.Parameters.Add(new CodeSnippetExpression(sb.ToString()));
    }
    else
    {
     methodcall.Parameters.Add(new CodePrimitiveExpression(null));
    }
 
    statements.Add(methodcall);
   }
  }
 }
}

And now the generated code looks like:

this.constantsExtenderProvider1.SetConstants(this.button1, new string[] {
    WindowsApplication1.Constants.Operation1,
    WindowsApplication1.Constants.Operation5
});

这篇关于是否有可能控制IExtenderProvider如何格式在Windows窗体设计code的输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆