代码之家  ›  专栏  ›  技术社区  ›  Ryan Lundy

UserControl作为一个接口,但在设计器中可见

  •  7
  • Ryan Lundy  · 技术社区  · 16 年前

    UserControl s.每个 用户控件 用户控件 除了其自身的特定成员之外,还包括方法、属性等。

    我一直在想一种降低处理这些问题复杂性的方法 用户控件 用户控件

    public class MyGiantForm
    {
        ICustomerName cName;
    
        public MyForm()
        {
            InitializeComponent();
    
            var uc = new SomeCustomerNameUserControl();
            this.Controls.Add(uc);
            cName = uc;
        }
    }
    

    SomeCustomerNameUserControl ICustomerName ,自然,和 包含我真正关心的特定属性(例如, FirstName LastName 用户控件 通过 cName 成员,而不是被所有人击倒 用户控件 成员们,我只接收那些 I客户名称 .

    一切都很好,但问题是,如果我这样做,我就看不见了 用户控件 在表单的设计界面上?

    编辑:

    然而,我对其他方法很感兴趣,即使它更复杂。使用IDesignerHost似乎有一些方法可以做到这一点,但我找不到任何适用的例子。

    8 回复  |  直到 16 年前
        1
  •  6
  •   Bob Nadler    16 年前

    如果 SomeCustomerNameUserControl 定义如下:

    class SomeCustomerNameUserControl : UserControl, ICustomerName
    {
    }
    

    ICustomerName cName = someCustomerNameUserControl1;
    

        2
  •  6
  •   Joe White    16 年前

    有一种方法可以实现你想要的——隐藏你不想看到的成员——但让它自动应用,而不需要其他人使用自定义界面进行合作。您可以通过重新引入所有不想看到的成员,并用属性标记它们来实现。

    例如,当基类属性对特定后代没有任何意义时,Windows窗体就是这样做的。例如,Control有一个Text属性,但Text属性在TabControl上没有意义。因此,TabControl覆盖了Text属性,并在其覆盖中添加了属性,说“顺便说一句,不要在属性网格或Intellisense中显示我的Text属性。”该属性仍然存在,但由于你从未见过它,它不会妨碍你。

    如果你添加一个 如果某个成员(属性或方法)具有属性,则Intellisense将不再在其代码完成列表中显示该成员。如果我正确理解了你的问题,那么这就是你想要实现的大事:让应用程序代码难以意外使用成员。

    对于属性,您可能还想添加 [可浏览(false)]

    这些将使意外使用方法/属性变得非常困难。然而,它们仍然不能保证。如果你确实需要保证,那么就加入一个

    如果基成员是虚拟的,您可能希望覆盖它,并让您的覆盖简单地调用base。不要抛出异常,因为在正常的事件过程中,基类可能会调用被重写的成员。另一方面,如果基成员不是虚拟的,那么你想使用“new”而不是“override”,你可以决定你的实现是应该调用基,还是只是抛出一个异常——无论如何都不应该有人使用你重新引入的成员,所以这不重要。

    public class Widget : UserControl
    {
        // The Text property is virtual in the base Control class.
        // Override and call base.
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Obsolete("The Text property does not apply to the Widget class.")]
        public override string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }
    
        // The CanFocus property is non-virtual in the base Control class.
        // Reintroduce with new, and throw if anyone dares to call it.
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Obsolete("The CanFocus property does not apply to the Widget class.")]
        public new bool CanFocus
        {
            get { throw new NotSupportedException(); }
        }
    
        // The Hide method is non-virtual in the base Control class.
        // Note that Browsable and DesignerSerializationVisibility are
        // not needed for methods, only properties.
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("The Hide method does not apply to the Widget class.")]
        public new void Hide()
        {
            throw new NotSupportedException();
        }
    }
    

        3
  •  4
  •   Community CDub    8 年前

    “我希望ICustomerName成为

    你遇到的问题是,你的表单和它所承载的控件有两种完全不同的用途。Visual Studio或winforms中没有内置的技巧可以为您巧妙地解决这个问题。这可能是可能的,但有一种更清晰、面向对象的方法可以将这两种与控件交互的方法分开。

    如果你想隐藏这些对象从UserControl继承的事实,只想把它们当作 IDoSomeThingYouShouldDealWith

    idea covered here in more detail :

    public interface ICustomerName
        {
            void ShowName(string theName);
        }
    
        public partial class Form1 : Form, ICustomerName
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            #region ICustomerName Members
    
            public void ShowName(string theName)
            {
                //Gets all controls that show customer names and sets the Text propert  
                //totheName
            }
    
            #endregion
        }
    
        //developers program logic into this class 
        public class Form1Controller
        {
            public Form1Controller(ICustomerName theForm) //only sees ICustomerName methods
            {
                //Look, i can't even see the Form object from here
                theForm.ShowName("Amazing Name");
            }
        }
    
        4
  •  3
  •   to StackOverflow    16 年前

    使用设计器添加UserControl后,可以在“属性”窗口中将GenerateMember设置为false,以禁止生成成员。

    foreach(Control control in this.Controls)
    {
        cName = control as ICustomerName;
        if (cName != null) break;
    }
    

    cName将是对UserControl的唯一引用。

        5
  •  1
  •   Joseph    16 年前

    您可以编写一个扩展方法,允许您返回窗体上实现接口的任何控件。

    public static class FormExtensions
    {
        public static IDictionary<string, T> GetControlsOf<T>(this Form form) 
               where T: class
        {
            var result = new Dictionary<string, T>();
            foreach (var control in form.Controls)
            {
                if ((control as T) != null)
                    result.Add((control as T).Tag, control as T);
            }
            return result;
        }
    }
    

    this.GetControlsOf<ICustomerName>()["NameOfControlHere"];
    

    如果它返回多个用户控件,您需要以某种方式处理它,也许可以通过向接口添加Tag属性来唯一跟踪每个用户控件或其他类似内容,如下所示

    public partial class UserControl1 : UserControl, ICustomerName
    {
         public string Tag { get { return this.Name; } }
    }
    

    然后,您可以从设计器将用户控件拖放到窗体上。标记将始终返回控件的名称,这将允许您通过IDictionary的接口直接访问控件。作为开发人员,您可以在控件的名称中放入他们想要的任何唯一标识符,并将其传递到接口。

    此外,应该注意的是,这种方法还允许您在解决方案中的所有表单上使用它。

    您唯一需要做的另一件事是将GenerateMember设置为false。

        6
  •  0
  •   Botz3000 Amir Sheng    16 年前

    你也可以按照Bob说的那样做,但在构造函数中分配所有成员变量,然后你就可以把它放在一个地方了。

        7
  •  0
  •   Mike Post    16 年前

    看起来你几乎想要实现一个中介模式。您不必直接处理无数用户控件中的每一个,而是通过中介与它们进行交互。每个中介都将定义您希望从每个控件看到的瘦界面。这将通过使您的设计更加明确和简洁来降低整体复杂性。例如,您不需要其中一个控件上可用的20个属性和50个方法。相反,你需要处理该控件的中介,它定义了你真正关心的2个属性和5个方法。所有内容都会显示在设计器中,但应用程序的其他部分不会与这些控件交互——它们会与中介交互。

    这种方法的一大优点是它大大简化了您的维护。如果你决定因为实现不好而需要重写MyCrappyUserControl,你只需要更新该控件的中介类。所有其他与控件交互的类都是通过中介进行的,并且不会改变。

        8
  •  -3
  •   M. Jahedbozorgan    16 年前

    假设MyUserControl的定义如下:

    class MyUserControl : UserControl, IMyInterface
    {
        // ...
    }
    

    那么在你的表格中,你应该有这样的东西:

    public class MyForm : Form
    {
        IMyInterface cName;
    
        public MyForm()
        {
            InitializeComponent();
    
            cName = new MyUserControl();
            Controls.Add((UserControl)cName);
        }
    }
    

    这样,cName是访问此用户控件实例的唯一方法。

    推荐文章