【问题标题】:User Control as container at design time在设计时将用户控件作为容器
【发布时间】:2010-04-22 22:10:12
【问题描述】:

我正在设计一个简单的扩展控件。

我从UserControl派生,绘制内部控件,构建,运行;没事。

由于内部控件是一个面板,我想在设计时将它用作容器。确实我已经使用了这些属性:

[Designer(typeof(ExpanderControlDesigner))]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] 

我说太好了。但不是……

结果是我可以在设计时将其用作容器,但是:

  • 添加的控件返回已嵌入用户控件的内部控件
  • 即使我将在设计时添加的控件推到顶部,在运行时它又会返回到嵌入到用户控件的控件上
  • 我无法在设计时将容器区域限制为面板区域

我错过了什么?这是完整的代码......为什么这个sn-p代码不起作用?

[Designer(typeof(ExpanderControlDesigner))]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))] 
public partial class ExpanderControl : UserControl
{
    public ExpanderControl()
    {
        InitializeComponent();
....

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] 
internal class ExpanderControlDesigner : ControlDesigner
{
    private ExpanderControl MyControl;

    public override void Initialize(IComponent component)
    {
        base.Initialize(component);

        MyControl = (ExpanderControl)component;

        // Hook up events
        ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService));
        IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService));

        s.SelectionChanged += new EventHandler(OnSelectionChanged);
        c.ComponentRemoving += new ComponentEventHandler(OnComponentRemoving);
    }

    private void OnSelectionChanged(object sender, System.EventArgs e)
    {

    }

    private void OnComponentRemoving(object sender, ComponentEventArgs e)
    {

    }

    protected override void Dispose(bool disposing)
    {
        ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService));
        IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService));

        // Unhook events
        s.SelectionChanged -= new EventHandler(OnSelectionChanged);
        c.ComponentRemoving -= new ComponentEventHandler(OnComponentRemoving);

        base.Dispose(disposing);
    }

    public override System.ComponentModel.Design.DesignerVerbCollection Verbs
    {
        get
        {
            DesignerVerbCollection v = new DesignerVerbCollection();

            v.Add(new DesignerVerb("&asd", new EventHandler(null)));

            return v;
        }
    }
}

我找到了很多资源(Interactiondesignedlimited area),但没有什么对操作有用...

实际上有一个技巧,因为 System.Windows.Forms 类可以被设计(像往常一样)并在运行时具有正确的行为(例如 TabControl)。

【问题讨论】:

    标签: c# winforms user-controls


    【解决方案1】:

    ParentControlDesigner 不知道您想要做什么。它只知道您希望您的 UserControl 成为一个容器。

    您需要做的是实现自己的设计器,在面板上启用设计模式:

        using System.ComponentModel;
        using System.Windows.Forms;
        using System.Windows.Forms.Design;
    
        namespace MyCtrlLib
        {
            // specify my custom designer
            [Designer(typeof(MyCtrlLib.UserControlDesigner))]
            public partial class UserControl1 : UserControl
            {
                public UserControl1()
                {
                    InitializeComponent();
                }
    
                // define a property called "DropZone"
                [Category("Appearance")]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
                public Panel DropZone
                {
                    get { return panel1; }
                }
            }
    
            // my designer
            public class UserControlDesigner  : ParentControlDesigner
            {
                public override void Initialize(System.ComponentModel.IComponent component)
                {
                    base.Initialize(component);
    
                    if (this.Control is UserControl1)
                    {
                        this.EnableDesignMode(
                           (UserControl1)this.Control).DropZone, "DropZone");
                    }
                }
            }
        }
    

    我从 CodeProject 上的 Henry Minute 了解到这一点。有关该技术的一些改进,请参阅链接。

    【讨论】:

    • 有效!但实际上它没有以下缺陷:您可以移动/调整“WorkingArea”(哪些差异有“DropZone”?)但在运行时它不会反映;设计时掺杂的控件无法在容器边界上对齐。
    • 我也有同样的两个问题,想知道如何解决
    • 我不知道如何处理这些问题。你看链接了吗?他可能已经用他的增强版解决了这些问题。 codeproject.com/KB/miscctrl/NestedControlDesigner.aspx
    • 我知道这是旧东西,但我发现如果你让 DropZone 停靠,则无法再从设计器中移动控件或调整其大小。如果您需要在非常特定的地方进行控制,您可以考虑使用两个面板。一个外部面板可以根据您的需要仔细定位,而一个内部面板则已装满码头并用作放置区。
    • 我上面的评论解决了这个问题,但是对于这个特殊的用例,它也禁用了自动滚动功能。这确实是一个问题。希望我的评论仍然有助于让某人朝着正确的方向前进。如果我解决它,我将继续自己戳它并再次发布。
    【解决方案2】:

    除了上面的答案。在 cmets 中提到,用户可以拖动 WorkingArea。我对此的解决方法是将 WorkingArea 面板包含在另一个面板中,将其设置为 Dock.Fill。为了禁止用户将其改回,我创建了一个覆盖和隐藏 Dock 属性的类 ContentPanel:

    class ContentPanel : Panel
    {
        [Browsable(false)]
        public override DockStyle Dock
        {
            get { return base.Dock; }
            set { base.Dock = DockStyle.Fill; }
        }
    }
    

    对我来说,这使它足够安全。我们只是在内部使用控件,所以我们主要是想防止开发人员不小心拖动东西。无论如何,肯定有办法搞砸的。

    【讨论】:

      【解决方案3】:

      为防止工作区在设计器中移动/调整大小,您必须为该工作区创建一个类,该类对设计器隐藏 Location、Height、Width、Size 属性:

      public class WorkingArea : Panel
      {
          [Browsable(false)]
          [EditorBrowsable(EditorBrowsableState.Never)]
          [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
          public new Point Location
          {
              get
              {
                  return base.Location;
              }
              set
              {
                  base.Location = value;
              }
          }
      ...
      }   
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多