how to add dynamically and remove a user control f

2019-09-20 20:10发布

问题:

I am struggling in adding a dynamic and removing a user control into the form. I have a form and inside my form I have a panel which it has a static control.

What I am trying to achieved is to add the user control into the panel. Though it was easy to add but I know there is a better way out there to do this.

Adding a user control to my panel by clicking a button in the 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.

Now, I get stacked here in removing the user control that was added and trying to display again the control that was in the panel that was been removed or cleared.

On my user control there is a back button on that back button I am trying to dispose the user control. But after that the original control is no longer there and the panel is empty already.

Any suggestions?

回答1:

You could add an instance variable to your form to keep track of the previous control. This assumes that there will only ever be one control in the panel.

In your class:

private Control _previousPanelContent;

then in your method:

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

then later when you want to go back:

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


回答2:

Here's a simple example of the Event approach mentioned in the Comments above.

The UserControl with a "Back" event:

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

}

The Form then creates the UserControl and subscribes to the Event:

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

}


回答3:

You are declaring your user control inside your button callback function (callback function is a function called at runtime when an event occurs, such as a button click etc.). This means that the variable holding your user control is inaccessible outside it, and therefore you are not able to use it from another callback function.

Instead of doing this:

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

Try declaring a property that will hold the user control, in order to use it elsewhere:

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


回答4:

I collected the solutions above (mostly the first of @Idle_Mind) I just added and adjusted some lines ; I will use his sentences:


Here's a simple example of the Event approach mentioned in the Comments above.

The UserControl with a "Back" event:

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

}

The Form then creates the UserControl and subscribes to the Event:

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

}

And, don't forget to set btnBack_Click for click of the UserControl's back button.

I hope this is helpful, it worked perfectly at my side ; I can send or share the full VS project (VS2012).



回答5:

I hope it works for you,

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


回答6:

I combine the answers of idle_mind,rdavisau and fabrice. I used rdavisau code in getting back the controls and idle_mind for the back event in the usercontrol and fabrice for his some modifications in the form.. I wish i can split the bounty into three,so I give it to idle mind..thanks all

I created a class:

 class GetControls
{

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

}

on my main form here is the revised code.

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


    }

and to retrieve the controls

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