如何在表单中动态添加和删除用户控件

how to add dynamically and remove a user control from a user control in a form

我正在为向表单中添加动态和删除用户控件而苦苦挣扎。我有一个表单,在我的表单中有一个面板,它有一个静态控件。

我想要实现的是将用户控件添加到面板中。虽然添加起来很容易,但我知道有更好的方法可以做到这一点。

通过单击表单中的按钮将用户控件添加到我的面板。

private void btnadd_Click(object sender, EventArgs e)
{
    UserControl1 usr = new UserControl1

    pnlUI.SuspendLayout();
    pnlUI.Controls.Clear();
    pnlUI.Controls.Add(usr);
    pnlUI.ResumeLayout(false);
}
// This one adds it and clearing the control that was already in the panel of the form.

现在,我忙于删除添加的用户控件并尝试再次显示面板中已删除或清除的控件。

在我的用户控件上,那个后退按钮上有一个后退按钮,我正在尝试处理该用户控件。但是之后原来的控件已经不存在了,面板已经是空的了。

有什么建议吗?

您可以在表单中添加一个实例变量来跟踪上一个控件。这假定面板中永远只有 一个 控件。

在你的class中:

private Control _previousPanelContent;

然后在你的方法中:

private void btnadd_Click(object sender, EventArgs e)
{
    UserControl1 usr = new UserControl1();

    pnlUI.SuspendLayout();

    // check if there's already content in the panel, if so, keep a reference.
    if (pnlUI.Controls.Count > 0)
    {
        _previousPanelContent = pnlUI.Controls[0];
        pnlUI.Controls.Clear();
    }

    pnlUI.Controls.Add(usr);

    pnlUI.ResumeLayout(false);
}

然后当你想回去的时候:

    pnlUI.SuspendLayout();
    pnlUI.Controls.Clear();

    // if the previous content was set, add it back to the panel 
    if (_previousPanelContent != null)
    {
        pnlUI.Controls.Add(_previousPanelContent);
    }

    pnlUI.ResumeLayout(false);

下面是上面评论中提到的事件方法的一个简单示例。

带有 "Back" 事件的用户控件:

public partial class UserControl1 : UserControl
{

    public event dlgBack Back;
    private UserControl1 _previous = null;
    public delegate void dlgBack(UserControl1 sender, UserControl1 previous);

    public UserControl1(UserControl1 previous)
    {
        InitializeComponent();
        this._previous = previous;
    }

    private void btnBack_Click(object sender, EventArgs e)
    {
        if (Back != null)
        {
            Back(this, _previous);
        }
    }

}

然后窗体创建用户控件并订阅事件:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        UserControl1 prevUsr = pnlUI.Controls.OfType<UserControl1>().FirstOrDefault();
        UserControl1 usr = new UserControl1(prevUsr);
        usr.Back += usr_Back;
        pnlUI.Controls.Clear();
        pnlUI.Controls.Add(usr);
    }

    void usr_Back(UserControl1 sender, UserControl1 previous)
    {
        pnlUI.Controls.Remove(sender);
        if (previous != null)
        {
            pnlUI.Controls.Add(previous);
        }
    }

}

希望对你有用,

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private int count = 0;
    private LinkedList<UserControl1> lstControls = new LinkedList<UserControl1>();

    private void btnAdd_Click(object sender, EventArgs e)
    {
        var c = new UserControl1();
        if (pnlUI.Controls.Count > 0)
        {
            lstControls.AddLast(pnlUI.Controls[0] as UserControl1);
            pnlUI.Controls.Clear();
        }
        c.lblTitle.Text = "Control #" + (++count).ToString();
        pnlUI.Controls.Add(c);
    }

    private void btnBack_Click(object sender, EventArgs e)
    {
        if (lstControls.Last != null)
        {
            var lastControl = lstControls.Last.Value;
            pnlUI.Controls.Clear();
            pnlUI.Controls.Add(lastControl);
            lstControls.RemoveLast();
        }
    }
}

您正在 按钮回调函数中声明您的用户控件(回调函数是在事件发生时在运行时调用的函数,例如单击按钮等)。 这意味着持有您的用户控件的变量在它之外是不可访问的,因此您不能从另一个回调函数中使用它。

而不是这样做:

private void btnadd_Click(object sender, EventArgs e)
{
    //This is not accessible outside the callback function.
    UserControl1 usr = new UserControl1();

    pnlUI.SuspendLayout();
    pnlUI.Controls.Clear();
    pnlUI.Controls.Add(usr);
    pnlUI.ResumeLayout(false);
}

尝试声明一个 属性 来保存用户控件,以便在其他地方使用它:

//Declare a private property - you can adjust the access level of course,
//depending on what you need.
//You can even declare a field variable for the same cause,such as
//private UserControl _myUserControl;

//This declaration is in the class body.
private UserControl MyUserControl { get; set; }

//Your addition callback function.
private void btnadd_Click(object sender, EventArgs e)
{
    //The user control is now assigned to the property.
    MyUserControl = new UserControl1();

    pnlUI.SuspendLayout();
    pnlUI.Controls.Clear();
    pnlUI.Controls.Add(MyUserControl);
    pnlUI.ResumeLayout(false);
}

//Your removal callback function.
private void btnremove_Click(object sender, EventArgs e)
{
    //...
    //Use the property value here.
    pnlUI.Controls.Remove(MyUserControl);
    //...
}

我收集了上面的解决方案(主要是@Idle_Mind的第一个)我只是添加并调整了一些行;我会用他的句子:


下面是上面评论中提到的事件方法的一个简单示例。

带有 "Back" 事件的用户控件:

No Change here

public partial class UserControl1 : UserControl
{

    public event dlgBack Back;
    private UserControl1 _previous = null;
    public delegate void dlgBack(UserControl1 sender, UserControl1 previous);

    public UserControl1(UserControl1 previous)
    {
        InitializeComponent();
        this._previous = previous;
    }

    private void btnBack_Click(object sender, EventArgs e)
    {
        if (Back != null)
        {
            Back(this, _previous);
        }
    }

}

然后窗体创建用户控件并订阅事件:

Let take a look at commented lines

public partial class Form1 : Form
{
    //prevUsr  is global instead
    private UserControl1 prevUsr = null;
    public Form1()
    {
        InitializeComponent();
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        //prevUsr is removed from here
        //UserControl1 prevUsr = pnlUI.Controls.OfType<UserControl1>().FirstOrDefault();
        UserControl1 usr = new UserControl1(prevUsr);
        usr.Back += usr_Back;
        pnlUI.Controls.Clear();
        pnlUI.Controls.Add(usr);
        //prevUsr is updated
        prevUsr = usr;
    }

    void usr_Back(UserControl1 sender, UserControl1 previous)
    {
        pnlUI.Controls.Remove(sender);
        //prevUsr is updated
        prevUsr = previous;
        if (previous != null)
        {
            pnlUI.Controls.Add(previous);
        }
    }

}

并且,不要忘记为单击 UserControl 的后退按钮设置 btnBack_Click。

我希望这对您有所帮助,它在我身边非常有效;我可以发送或共享完整的 VS 项目 (VS2012)。

我结合了idle_mind,rdavisau和fabrice的答案。我使用 rdavisau 代码取回控件,idle_mind 用于用户控件中的后退事件,以及用于他对表单进行一些修改的 fabrice。我希望我可以将赏金分成三部分,所以我把它放在空闲的头脑中..谢谢大家

我创建了一个 class:

 class GetControls
{

    private Control[] cntrl;
    public Control[] Previous
    {
    get
    { 
        return cntrl;
    }
        set
        {
            cntrl = value;
        }
    }

}

在我的主窗体上是修改后的代码。

  GetControls help = new GetControls();
  private void btnpay_Click(object sender, EventArgs e)
    {


        TenderUI usr = new TenderUI(prevUsr);
        usr.Back += usr_Back;

        help.Previous = pnlUI.Controls.OfType<Control>().ToArray(); 

        pnlUI.Controls.Clear();
        pnlUI.Controls.Add(usr);


    }

并检索控件

 void usr_Back(TenderUI sender, TenderUI previous)
    {
        pnlUI.Controls.Remove(sender);

        if (help.Previous != null)
        {
            foreach (Control ctr in help.Previous)
            {
                pnlUI.Controls.Add(ctr);
            }
        }
    }