【问题标题】:How do you prevent dragging controls out of a custom control at design time?如何防止在设计时将控件拖出自定义控件?
【发布时间】:2012-09-09 19:19:34
【问题描述】:

在此用户控件中,设计者将项目添加到表单上的此控件中,并动态地将它们放置在表单上。不幸的是,一旦这些控件显示在设计器中的表单上,我就可以抓住一个并将其拉到自定义控件之外。

如何防止这种情况发生?

编辑

请注意,我不是在寻找处理单选按钮的解决方案或替代方法,这只是在这种情况下的选择控制。如果它有助于在此处插入您想要的任何类型的控件(Button、Label、TextBox、CustomControl1),则此问题与处理具有集合/数组类型的属性有关。最重要的是,用户不应该能够在设计器中抓取任何这些控件,其中定义了该控件的实例并将其移动到其他地方。就像 DataGridView 或 ListView 一样,尽管对象类型不同,但用户必须使用属性来更改这些控件的内容。这就是我要寻找的行为。

RBLTest.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WFCL_Library
{
    public partial class RBLTest : UserControl
    {
        private RadioButton[] _items;

        private int leftSpacing = 100;
        private int topSpacing = 25;

        public RBLTest()
        {
            InitializeComponent();
        }

        private void RadioButtonList_Load(object sender, EventArgs e)
        {
            int curLeftPos = 0;
            int curTopPos = 0;
            foreach (RadioButton rb in _items)
            {
                rb.Location = new Point(curLeftPos, curTopPos);
                rb.Size = new Size(85, 17);

                curLeftPos += leftSpacing;

                if (curLeftPos > this.Width)
                {
                    curLeftPos = 0;
                    curTopPos += topSpacing;
                }

                this.Controls.Add(rb);                
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public RadioButton[] Items
        {
            get
            {
                return _items;
            }
            set
            {
                _items = value;
            }
        }
    }       
}

RBLTest.Designer.cs

namespace WFCL_Library
{
    partial class RBLTest
    {
        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // RBLTest
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Name = "RBLTest";
            this.Size = new System.Drawing.Size(407, 44);
            this.Load += new System.EventHandler(this.RadioButtonList_Load);
            this.ResumeLayout(false);

        }

        #endregion

    }
}

【问题讨论】:

  • 非常不清楚设计者如何分配 Items 属性。简单的解释是您将单选按钮放在 UserControl 顶部,而不是在它们内部。在将 UserControl 放置在表单上后,为 UserControl 内的控件启用设计模式需要自定义设计器。
  • 我不想为用户控件内部的控件设计控件,仅此而已。构建此控件,将其从工具箱拖到窗体上,然后选择 items 属性并添加新实例。它创建单选按钮并按预期相应地显示它们。出乎意料的是,您只需抓住其中一个单选按钮并将其从自定义控件中取出,然后将其从该自定义控件之外拖放到表单上。该按钮仍然是自定义控件中项目列表的一部分,即使它现在显示在它之外。

标签: c# visual-studio-2008 .net-3.5 custom-controls windows-forms-designer


【解决方案1】:

嗯,这取决于你想怎么做。首先,我不喜欢允许直接访问我的用户控件上的控件。出于这个原因,我确保没有任何控件可以公开访问。我所做的是将所有内容设为私有(或有时受保护,因为派生类具有一定的灵活性会很好),然后我创建属性来访问控件的必须可访问的属性和由父容器处理的事件。

如果这一切对你来说真的无关紧要,那么我相信你正在寻找的属性是 Control.Locked 属性。在上面的代码中,将动态控件添加到 Controls 集合后,将 Locked 设置为 true。所以:

            this.Controls.Add(rb);
            rb.Locked = true;


试试这样的:

    public class RadioButtonProperties
    {
        private RadioButton _realtedRadioButton = new RadioButton();

        public RadioButtonProperties(RadioButton radio)
        {
            _realtedRadioButton = radio;

            Name = radio.Name;
            Checked = radio.Checked;
            //add other properties
        }

        public string Name
        {
            get
            {
                //logic to to handle if checkbox is null here

                return _realtedRadioButton.Name;
            }

            set
            {
                //logic to to handle if checkbox is null here

                _realtedRadioButton.Name = value;
            }
        }

        public bool Checked
        {
            get
            {
                //logic to to handle if checkbox is null here

                return _realtedRadioButton.Checked;
            }

            set
            {
                //logic to to handle if checkbox is null here

                _realtedRadioButton.Checked = value;
            }
        }
    }

现在在您的自定义控件中,您无需公开访问整个单选框数组,而是授予对数组表示的访问权限,仅公开您想要的单选框属性。例如:

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]  
    public List<RadioButtonProperties> Items { get; set; }

【讨论】:

  • Locked 只是设计器中的一个属性,在后面的代码中是不可访问的。这是我的第一个想法,因为已经有一个属性,但是唉,不起作用。
  • 在这种情况下,您确实不能允许公共访问您的控件。如果您只想取消/选中复选框或查看复选框是否未选中/选中,那么您可以使用 Indexed Properties 来获得一些乐趣。例如:myControl[0] = true;否则使用带有公共方法的私有控件。
  • 这与设置属性无关,设计人员可以单击自定义控件之外的单选按钮并将其拖动到表单上,从而将其注册到两者都会产生大问题:\
  • 事实上,我不得不怀疑这是否与它有关。您允许公开访问您的 Items 数组,从而可以公开访问存储在其中的所有内容。请参阅我提供的代码以支持我的意思的更新答案,这可能值得一试。
  • 我应该已经阅读了你的初始段落几次,可访问性是关键。赚了,像魅力一样工作!应该注意的是,在执行此操作时 RadioButtonProperties 需要一个具有零参数的默认构造函数才能在 Visual Studio 中“开箱即用”工作,否则从 proreties 添加项目会引发异常。
猜你喜欢
  • 2013-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多