在拖放过程中修改工具箱项
本文关键字:工具箱 修改 过程中 拖放 | 更新日期: 2023-09-27 18:17:37
我正在使用DesignSurface类,我遇到了一个令人沮丧的问题,我似乎无法弄清楚。我正在从我的工具箱中拖动项目并将它们放到我的表单上,没有问题,但我想修改这些项目的属性,因为它们被放置在DesignSurface上。因此,例如,如果我将标签拖到DesignSurface上,我可能会改变控件的BackColor的值。我知道ToolboxItem暴露了CreateComponents(),它接受属性的可选参数,但这是由低级API调用的,我不知道在哪里或如何覆盖它,所以我可以提供我自己的值。有人有什么想法吗?谢谢!
这不是一个答案,我只是想展示我对你的问题的发现。我认为你应该有自己的方式来访问你自己的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
OK。我没有发现任何其他事件更好,最合适的事件应该是ComponentAdded
或ComponentAdding
,但它们都不工作。
我还有一个问题,我尝试的样本项目是一个CustomFormsDesigner
,它像其他正常的Windows窗体应用程序一样运行,它显示了一个工具箱,一个DesignSurface和一个属性网格。我做的一切都是在运行之后。那你的案子呢?我的意思是,当你把控件拖放到DesignSurface上时,你仍然处于Visual Studio窗口的设计阶段?还是在您自己的应用程序(作为设计器)窗口中?
虽然我觉得这有点"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;
}
}
一些明显的缺陷:
- 这个项目只会创建一个标签控件
- 这个项目只会根据公共字符串属性设置标签控件的文本属性。
为了克服这些问题,可以将项目扩展为更像基本的ToolboxItem(实现一个接受Type参数的actor,允许传入一个属性名称/值的字典,以便在事后设置,等等)
此外,这破坏了我从工具箱到设计界面的拖放功能,这尤其令人沮丧,因为它不太明显。问题出在我的工具箱服务实现的DeserializeToolboxItem方法中。
原来是这样的:
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
return (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));
}
问题是,转换到ToolboxItem返回null,因为对象的类型是SurfaceToolboxItem,所以我修改了方法,看起来像这样:
ToolboxItem IToolboxService.DeserializeToolboxItem(object serializedObject)
{
var data = (ToolboxItem) ((DataObject) serializedObject).GetData(typeof (ToolboxItem));
return data ?? (ToolboxItem)((DataObject)serializedObject).GetData(typeof(SurfaceToolboxItem));
}
因此支持我的扩展以及默认的ToolboxItem的。