Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在拖放过程中修改ToolboxItem_C#_Winforms - Fatal编程技术网

C# 在拖放过程中修改ToolboxItem

C# 在拖放过程中修改ToolboxItem,c#,winforms,C#,Winforms,我正在使用DesignSurface类,我遇到了一个令人沮丧的问题,我似乎无法解决。我正在从工具箱中拖动项目,并将其毫无问题地放到表单中,但我希望在将这些项目放到DesignSurface中时修改其属性。因此,例如,如果我将标签拖到设计图面上,我可能会更改控件背景色的值。我知道ToolboxItem公开CreateComponents(),它接受一个可选的属性参数,但这是由较低级别的API调用的,我不知道在哪里或如何重写它,以便提供自己的值。有人有什么想法吗?谢谢 这不是答案,我只是想展示一下我

我正在使用DesignSurface类,我遇到了一个令人沮丧的问题,我似乎无法解决。我正在从工具箱中拖动项目,并将其毫无问题地放到表单中,但我希望在将这些项目放到DesignSurface中时修改其属性。因此,例如,如果我将标签拖到设计图面上,我可能会更改控件背景色的值。我知道ToolboxItem公开CreateComponents(),它接受一个可选的属性参数,但这是由较低级别的API调用的,我不知道在哪里或如何重写它,以便提供自己的值。有人有什么想法吗?谢谢

这不是答案,我只是想展示一下我对你的问题的发现。我认为您应该有自己的方式访问自己的
工具箱
,这个
工具箱
实现接口
IToolboxService
,这个接口有一个名为
GetSelectedToolboxItem(IDesignerHost)
的方法。我认为您必须实现该方法来指定如何获取所选项,我认为您的
工具箱
应该有一些控制来保存工具箱项列表,它可以是
列表框

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

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;
};
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   return (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));
}
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   var data = (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));

   return data ?? (ToolboxItem)((DataObject)serializedObject).GetData(typeof(SurfaceToolboxItem));
 }
我在一个项目中进行了测试,该项目实现了一个非常复杂的
IDesignerHost
,它提供了一种方法来创建要测试的
主机。当在
设计图面上拖放控件时,它仍然不受
TransactionClosed
中的代码的影响,我必须执行类似
调整控件大小、移动…
的操作,然后引发
TransactionClosed
事件,并显示
DisplayName
OK。我没有发现其他更好的事件,最合适的事件应该是
ComponentAdded
ComponentAdding
,但它们都不起作用

我还有一个问题,我尝试的示例项目是一个
CustomFormsDesigner
,它与其他普通Windows窗体应用程序一样运行,它显示一个工具箱、一个设计图面和一个属性网格。我在运行它之后做所有事情。但是你的案子呢?我的意思是,当您将控件拖放到DesignSurface上时,您仍然处于Visual Studio窗口的设计阶段?还是在您自己的应用程序(作为设计师)窗口中


我不得不说,这个问题对我来说太复杂了。多亏了你,我知道这类应用程序。

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

我最终做的是根据我读到的一篇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;
    }

}
一些明显的缺陷:

  • 此项将仅创建标签控件
  • 此项将仅基于公共字符串属性设置所述标签控件的文本属性
为了克服这些问题,可以扩展该项,使其更像基本ToolboxItem(实现接受类型参数的ctor,允许传入属性名称/值的字典,以便在事实发生后进行设置,等等)

此外,这还破坏了我从工具箱到设计界面的拖放功能,这尤其令人沮丧,因为原因不太明显。问题出在工具箱服务实现的反序列化ToolboxItem方法中

原来是这样的:

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;
};
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   return (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));
}
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   var data = (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));

   return data ?? (ToolboxItem)((DataObject)serializedObject).GetData(typeof(SurfaceToolboxItem));
 }
问题是对ToolboxItem的转换返回null,因为对象的类型为SurfaceToolboxItem,所以我修改了方法,使其如下所示:

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;
};
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   return (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));
}
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
   var data = (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));

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

因此支持我的扩展和默认ToolboxItem

您的意思是说
设计图面上有一些项目
,您希望在设计时(通过“属性”窗口)修改这些项目的某些属性吗?您的
DesignSurface
看起来像什么?它有点像
面板吗?您的问题对我来说不够清楚。DesignSurface是一个用户控件。我实际上想做的是,当用户将一个控件放到UserControl上时,我想在它实际显示在表面之前修改该控件的一些属性。当然,如果我想在控件的值出现在DesignSurface上之后修改它们,我只需要配置一个PropertyGrid。这对我来说有点奇怪?为什么一定要这样做?我正在开发的应用程序基本上是试图复制Visual Studio中报表设计器中的一小部分功能,以便向用户公开。我试图解决的问题是,工具箱实际上包含报表字段名称,当用户在DesignSurface上拖放字段时,我需要一种方法来保持x标签实际上是数据集中的名称字段。我还没有想出更好的方法来处理这个问题,坦白说,这是我第一次被要求主持运行时设计器,所以这很有挑战性。嘿,金。有几件事。我应该更清楚:我实际上使用的是System.ComponentModel.Design.DesignSurface,因此与设计师合作的许多细节都从我身上抽象了出来。我的RootComponent是UserControl类型,您的代码确实可以工作,每次向其添加控件时它都会触发,但我更具体的问题是:我工具箱中的所有“工具”都是Label类型,它们的DisplayName设置为报表数据集中的字段名。我需要那个DisplayName值,这样我就知道要将控件绑定到哪个字段。但我愿意接受suggestion@abszero我发现我的解决方案有问题,它只有在我拖动控件时才起作用