在拖放过程中修改ToolboxItem

时间:2013-06-08 21:54:40

标签: c# winforms

我正在使用DesignSurface类,我遇到了令人沮丧的问题,我似乎无法弄明白。我正在从我的工具箱拖动项目并将它们放到我的表单上没有问题,但我想修改这些项目的属性,因为它们被放置在DesignSurface上。因此,例如,如果我将标签拖到DesignSurface上,我可能会更改控件的BackColor的值。我知道ToolboxItem暴露了CreateComponents(),它接受一个可选的属性参数,但这是由较低级别的API调用的,我没有看到在何处或如何覆盖它,所以我可以提供自己的值。有没有人有任何想法?谢谢!

2 个答案:

答案 0 :(得分:1)

这不是答案,我只是想表明我发现你的问题。我认为您应该有自己的方式来访问自己的Toolbox,而Toolbox实现接口IToolboxService,此接口有一个名为GetSelectedToolboxItem(IDesignerHost)的方法。我认为你必须实现该方法来指定你如何获得所选项目,我认为你的Toolbox应该有一些控件来保存工具箱项目列表,它可以是ListBox ...

第二个重要的是IDesignerHost,据我所知,这可能是你感兴趣的内容。它应该与你的DesignSurface有一些关系。它有一些让你感兴趣的事件,比如:

IDesignerHost host = {some method to get it};
host.TransactionClosed += (s,e) => {
  ICollection selected = ((ISelectionService)host.GetService(typeof(ISelectionService))).GetSelectedComponents();                
  IComponent[] comps = new IComponent[selected.Count];
  selected.CopyTo(comps, 0);
  string displayName = YourToolBox.GetSelectedToolboxItem(host).DisplayName;
  ((Control)comps[0]).Text = displayName;
};

我在一个实现非常复杂IDesignerHost的项目中进行了测试,它有一个方法让我创建要测试的host。在DesignSurface上拖放控件时,它仍然不受TransactionClosed中代码的影响,我必须执行类似Resizing, Moving...控件的操作,然后TransactionClosed }事件被引发,它显示DisplayName确定。我没有发现任何其他更好的事件,最合适的事件应该是ComponentAddedComponentAdding,但它们都不起作用。

我还有一个问题,我尝试的示例项目是CustomFormsDesigner,它运行为其他常规Windows窗体应用程序,它显示了一个工具箱,一个DesignSurface和一个属性网格。运行之后我做了一切。但你的情况怎么样?我的意思是当你将控件拖放到DesignSurface上时,你仍处于Visual Studio窗口的设计时间?或者在您自己的应用程序(作为设计器)窗口中?

我不得不说,这个问题对我来说太复杂了。谢谢你,我知道这种应用。

答案 1 :(得分:0)

虽然我觉得这有点“hacky”但我不一定知道它是错的(如果它在技术上是“错误的”请给我一些关于最佳实践的反馈!)它解决了手头的问题。

我最终做的是根据我阅读的MSDN文章扩展ToolboxItem。

public class SurfaceToolboxItem : ToolboxItem
{
    private delegate void SetTextHandler(Control c, string text);
    public string ReportFieldName { get; set; }

    protected override IComponent[] CreateComponentsCore(IDesignerHost host)
    {
        var ctrl = (Label)host.CreateComponent(typeof(Label));
        var root = (Control) host.RootComponent;

        root.BeginInvoke(new SetTextHandler(SetText),
                         new object[] {ctrl, ReportFieldName});

        return new IComponent[]{ ctrl };
    }

    private void SetText(Control ctrl, string text)
    {
        ctrl.Text = text;
    }

}

一些明显的缺陷:

  • 此项目只会创建一个Label控件
  • 此项目只会根据公共字符串属性设置所述标签控件的text属性。

为了克服这些问题,可以将项目扩展为更像基础ToolboxItem(实现ctor接受Type参数,允许传入属性名称/值的字典以在事后设置等)< / p>

此外,这使我的拖放功能从我的工具箱破坏到设计界面,这特别令人沮丧,因为它并不是太明显的原因。问题出在我的Toolbox Service实现的DeserializeToolboxItem方法中。

最初它看起来像这样:

ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   return (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));
}

问题是由于对象是SurfaceToolboxItem类型,因此对ToolboxItem的强制转换返回null,因此我将方法修改为如下所示:

ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   var data = (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));

   return data ?? (ToolboxItem)((DataObject)serializedObject).GetData(typeof(SurfaceToolboxItem));
 }

因此支持我的扩展以及默认的ToolboxItem。