【问题标题】:creating items collection in a custom control在自定义控件中创建项目集合
【发布时间】:2016-06-20 11:40:21
【问题描述】:

我有一个继承自 WinForm 中的 Control 类的自定义控件。我的控件包含多个面板和其他 UIElement。

这就是我的控件应该看起来的样子

有一个数据库面板, 数据库面板仅包含一个复选框。

还有一个服务器面板, 服务器面板包含许多数据库面板和一个标签;标题标签。

最后是包含我所有服务器面板的容器面板。

我找到了这个Item Collection option for a User Control,但我无法真正理解它接受的答案。如果有人可以帮助更好地解释它,那就太好了。

另外,如果有人可以放一些链接来创建高级自定义控件。我整天都在阅读它,但我仍然无法理解这一切。是否有高级自定义控件的分步指南?

[编辑]

基本上我需要的是在我的自定义控件中创建一个自定义集合。目前,我的控件构建为我构建的 Winform 控件库,然后在我的主程序中使用。 所以在我的主程序中,我可以将组件拖放到我的表单上并使用它。

默认情况下,自定义控件将加载一个包含一个数据库的服务器。 如果需要,我想要的是能够在我的 MAIN 程序中添加/删除其他数据库/服务器

我无法准确解释我需要什么,因为我根本不明白整个自定义控件/项目集合是如何工作的,对此我深表歉意。我真的很感激一些能清楚地解释这些东西的链接

这是我的这个控件的代码:

此代码仅创建我的默认控件,但我无法添加。集合属性出现在我的属性窗口中,但是当我向其中添加项目并单击确定时,没有任何反应。

public class Database : System.Windows.Forms.Panel
{
    public CheckBox _ckbDatabase;

    public Database()
    {
        _ckbDatabase = new CheckBox();

        this.BackColor = _pnlDatabaseBackColor;
        this.Size = _pnlDatabaseSize;
        this.AutoSize = false;
        this.Height = 40;
        this.Width = 200;
        this.Location = _pnlDatabaseLocation;
        _ckbDatabase.Top = 10;
        _ckbDatabase.Left = 15;
        _ckbDatabase.TextAlign = _ckbdbTextAlignment;
        _ckbDatabase.Font = _ckbdbFont;
        _ckbDatabase.ForeColor = Color.White;

        this.Controls.Add(_ckbDatabase);

    }

    #Propterties
}

public class Server : System.Windows.Forms.Panel
{
    private Label _lblserver;
    private Database database;

    public Server()
    {
        _lblserver = new Label();
        database = new Database();
        this.BackColor = _pnlServerBackColor;
        this.Size = _pnlServerSize;
        this.AutoSize = false;
        _lblserver.Dock = _lblserverDock;
        _lblserver.Font = _lblsrvFont;
        _lblserver.BackColor = _lblServerBackColor;
        _lblserver.AutoSize = false;
        _lblserver.Text = SRV;

        database.Top = 35;
        database._ckbDatabase.Text = DB;

        this.Controls.Add(_lblserver);
        this.Controls.Add(database);
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DatabaseCollection DatabaseCollection { get; set; }

    #Propterties
 }

public class ServersCollection : CollectionBase
{
    public Server this[int index]
    {
        get { return (Server)List[index]; }
    }
    public void Add(Server server)
    {
        List.Add(server);
    }
    public void Remove(Server server)
    {
        List.Remove(server);
    }
}

【问题讨论】:

  • 这是怎么做到的?您是在发现服务器和数据库时在代码中构建此控件,还是只是一个内容永不改变的静态呈现?
  • @DonBoitnott 它是用代码构建的。如果我理解您的暗示,我将不需要 ObservableCollection。
  • 无论如何,这更像是一个 WPF 的东西,所以如果你愿意,你可能无法使用它。
  • 既然您已经拥有控制权,并且您已经在向其中添加服务器/数据库,我不确定我是否理解您的挣扎。只需创建一个类似该答案的课程并向其中添加项目即可。这只是数据。除非您需要设计时支持,否则关于 PropertyGrid 的部分无关紧要。
  • @DonBoitnott 我编辑了我的问题,我意识到我之前并没有真正解释清楚。请注意,我无法从我的收藏中添加/删除项目,我的代码不起作用。我真的很抱歉成为这样一个菜鸟:S

标签: winforms collections custom-controls


【解决方案1】:

像这样简单的东西怎么样:

public class Server {
    public string Name { get; set; }
    public List<Database> Databases { get; set; }

    public Server() {
        Databases = new List<Database>();
    }
}

public class Database {
    public string Name { get; set; }
    public bool Enabled { get; set; }
}

然后你可以像这样添加它:

        List<Server> servers = new List<Server>();

        Server serverA = new Server { Name = "Server A" };
        serverA.Databases.Add(new Database { Name = "Database 1", Enabled = true });
        serverA.Databases.Add(new Database { Name = "Database 2", Enabled = false });

        Server serverB = new Server { Name = "Server B" };
        serverB.Databases.Add(new Database { Name = "Database 1", Enabled = false });
        serverB.Databases.Add(new Database { Name = "Database 2", Enabled = false });

        servers.Add(serverA);
        servers.Add(serverB);

当您链接到项目集合部分时,您似乎希望能够在设计模式下添加服务器和数据库,但是您提到您想通过代码来实现?如果这不是您想要的,您需要向我们提供更多信息。

【讨论】:

    【解决方案2】:

    在我看来,你大部分时间都在那儿。首先,这是一个更完整的集合类:

    public class ServersCollection : IEnumerable<Server>
    {
        private List<Server> _servers = new List<Server>();
    
        public Server this[int index]
        {
            get { return _servers[index]; }
        }
    
        public IEnumerator<Server> GetEnumerator()
        {
            foreach (var server in _servers)
                yield return server;
        }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    
        public void Add(Server server)
        {
            _servers.Add(server);
        }
    
        public void Remove(Server server)
        {
            //You might consider a deliberate loop to evaluate a proper match
            //Don't forget to Dispose() it first!
            _servers.Remove(server);
        }
    
        public void Clear()
        {
            for (Int32 i = _servers.Count - 1; i >= 0; i--)
                _servers[i].Dispose();
            _servers.Clear();
        }
    }
    

    ServersCollection 类的实例添加到容器控件,即包含服务器面板的顶层:

    private ServersCollection _servers = new ServersCollection();
    public ServersCollection Servers { get { return _servers; } }
    

    使用它作为将Server 控件添加到它自己的控件集合的一种方式。

    Server 类中的DatabaseCollection 执行类似操作,再次将Database 面板添加到其控件集合中。

    然后,无论您拥有一个控件实例,您都可以访问它所拥有的集合:

    myControl.Servers
    //-or-
    myServer.Databases
    

    ...允许您添加/删除,例如:

    myControl.Servers.Add(new Server());
    //-or-
    myServer.Databases.Add(new Database());
    

    重点

    您的类是控件,但它们也拥有其他控件。正确使用Dispose 模式至关重要,否则您将在整个过程中遇到内存问题。

    我会删除这些行,除非您打算在表单设计时添加服务器/数据库(即固定条目或默认值),否则它们无关紧要:

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public DatabaseCollection DatabaseCollection { get; set; }
    

    最后,您可以(应该!)进一步使用该集合类,使用 Add()Remove() 的重载可以更好地根据多个实例来决定何时/如何/做什么,例如按名字?例如,您还可以添加另一个索引器以按名称获取,而不仅仅是索引(您可能不知道)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多