C# 如何在窗体中从用户控件中动态添加和删除用户控件

C# 如何在窗体中从用户控件中动态添加和删除用户控件,c#,user-controls,C#,User Controls,我很难在表单中添加动态控件和删除用户控件。我有一个窗体,在窗体内有一个面板,它有一个静态控件 我试图实现的是将用户控件添加到面板中。虽然这很容易添加,但我知道有更好的方法可以做到这一点 通过单击表单中的按钮将用户控件添加到“我的面板” private void btnadd_Click(object sender, EventArgs e) { UserControl1 usr = new UserControl1 pnlUI.SuspendLayout(); pnlU

我很难在表单中添加动态控件和删除用户控件。我有一个窗体,在窗体内有一个面板,它有一个静态控件

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

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

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.
现在,我在移除添加的用户控件并尝试再次显示面板中已移除或清除的控件时遇到了麻烦

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


有什么建议吗

您可以将实例变量添加到表单中,以跟踪上一个控件。这假设面板中只有一个控件

在你们班:

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);

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

带有“返回”事件的UserControl:

然后表单创建UserControl并订阅事件:

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);
        }
    }

}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}
私有void btnAdd_单击(对象发送者,事件参数e)
{
UserControl1 prevUsr=pnlUI.Controls.OfType().FirstOrDefault();
UserControl1 usr=新的UserControl1(prevUsr);
usr.Back+=usr\u Back;
pnlUI.Controls.Clear();
pnlUI.Controls.Add(usr);
}
void usr_Back(UserControl1发送方,UserControl1先前)
{
pnlUI.控件。移除(发送器);
如果(上一个!=null)
{
pnlUI.Controls.Add(上一个);
}
}
}

我希望它对你有用

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();
        }
    }
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
}
私有整数计数=0;
private LinkedList lstControls=new LinkedList();
私有void btnAdd_单击(对象发送者,事件参数e)
{
var c=newusercontrol1();
如果(pnlUI.Controls.Count>0)
{
lstControls.AddLast(pnlUI.Controls[0]作为UserControl1);
pnlUI.Controls.Clear();
}
c、 lblTitle.Text=“Control#”+(++count.ToString();
pnlUI.Controls.Add(c);
}
私有无效btnBack\u单击(对象发送者,事件参数e)
{
如果(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的第一个),我只是添加和调整了一些行;我将使用他的句子:



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

带有“返回”事件的UserControl:

此处无更改

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);
        }
    }

}
然后表单创建UserControl并订阅事件:

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
{
    //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);
        }
    }

}
公共部分类表单1:表单
{
//prevUsr是全球性的
private UserControl1 prevUsr=null;
公共表格1()
{
初始化组件();
}
私有void btnAdd_单击(对象发送者,事件参数e)
{
//prevUsr从此处删除
//UserControl1 prevUsr=pnlUI.Controls.OfType().FirstOrDefault();
UserControl1 usr=新的UserControl1(prevUsr);
usr.Back+=usr\u Back;
pnlUI.Controls.Clear();
pnlUI.Controls.Add(usr);
//prevUsr已更新
prevUsr=usr;
}
void usr_Back(UserControl1发送方,UserControl1先前)
{
pnlUI.控件。移除(发送器);
//prevUsr已更新
prevUsr=先前;
如果(上一个!=null)
{
pnlUI.Controls.Add(上一个);
}
}
}
另外,不要忘记设置btnBack\u Click以点击UserControl的back按钮


我希望这是有帮助的,它在我这边工作得很好;我可以发送或共享完整的VS项目(VS2012)。

我结合了idle_mind、rdavisau和fabrice的答案。我使用rdavisau代码返回控件,并在usercontrol和fabrice中为back事件空闲,以便对表单进行一些修改。。我希望我能把赏金分成三份,所以我把它交给懒惰的人。谢谢大家

我创建了一个类:

 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);


    }

为什么不添加另一个空白/默认用户控件,以替换已添加的(您正试图删除的)控件?在窗体/类级别声明一个变量,以保存对旧usercontrol的引用,以便以后可以检索它并将其添加回。这是Idle的建议,干净和简单,或者你可以有一个无形的控件,使其成为你的UC的父控件,从而将其移动到那里。@idle\我尝试了你的建议,但我的问题是我无法在用户控件上检索它。my back button位于用户控件上,该控件是通过使用自己的back button控件添加和删除的。因此:(1)将对旧Usercontrol的引用传递到新Usercontrol中,以便可以从UC内交换,或者(2)将引用存储在表单中,并使Usercontrol引发自定义的“back”事件,该事件由表单subsc
 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);
            }
        }
    }