问题
This may sound stupid, But I am having hard time to figure this out; any help would be appreciated:
I have two user controls called “Safety_Check” and “OEE_Track”. In my MainForm I have a panel called “pnl_main_controller” this is where I am displaying both my user controls. I have two buttons on my main form and I am dynamically switching between both without any issue.
Safety_Check User control;
public partial class Safety_Check : UserControl
{
private static Safety_Check _instance;
public static Safety_Check instance
{
get
{
if (_instance == null)
_instance = new Safety_Check();
return _instance;
}
}
public Safety_Check()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
///////------------------------
}
}
OEE_Track User control
public partial class OEE_Track : UserControl
{
private static OEE_Track _instance;
public static OEE_Track instance
{
get
{
if (_instance == null)
_instance = new OEE_Track();
return _instance;
}
}
public OEE_Track()
{
InitializeComponent();
}
}
MainForm:
public partial class MainForm : Form
{
private void btn_reg_Click(object sender, EventArgs e)
{
if (!pnl_main_controller.Contains(Safety_Check.instance))
{
pnl_main_controller.Controls.Add(Safety_Check.instance);
Safety_Check.instance.Dock = DockStyle.Fill;
Safety_Check.instance.BringToFront();
}
else
{
Safety_Check.instance.BringToFront();
} }
private void btn_OEE_Click(object sender, EventArgs e)
{
if (!pnl_main_controller.Contains(OEE_Track.instance))
{
pnl_main_controller.Controls.Add(OEE_Track.instance);
OEE_Track.instance.Dock = DockStyle.Fill;
OEE_Track.instance.BringToFront();
}
else
{
OEE_Track.instance.BringToFront();
}
}
What I am trying to do is I have a button called “Button1” on my “Safety_Check” Usercontrol, whenever I press this , I want “Safety_Check” to be disappear on “pnl_main_controller” and bring “OEE_Track” to the panel
回答1:
There are several solutions for interaction between controls. Controls are classes and like any other class they can interact with each other using their public properties and methods or using some mediator.
In this case, your controls don't need to know each other and don't need to interact to each other directly:
- They can ask another object which knows both controls, to do the job for them.
- Or they can raise their request notification and the one who subscribed to that notification, will serve it.
To ask another object to do the job for them you have multiple solutions. As an example you can implement a specific interface in the parent form and in the child controls, cast the parent to that specific interface and call a specific method which do the job for you.
For raising the request notification, an easy solution is relying on events. You can create an event in the child control and raise it when you need the parent do something for you. Then in the parent subscribe to that event and do the job.
Example - Using event
I assume you have UserControl1
having Button1
inside and you have handled Click
event of Button1
. Then you can create Button1Clicked
event and raise it when Button1
clicked:
public event EventHandler Button1Clicked;
private void Button1_Click(object sender, EventArgs e)
{
Button1Clicked?.Invoke(this, e);
}
Then in the parent form, subscribe for the event and do whatever you want:
private void userControl11_Button1Clicked(object sender, EventArgs e)
{
//Hide userControl11 and show userControl21
}
Example - Using interface
I assume, you have an interface having a few standard methods:
public interface IDoSomething
{
void DoSomething();
void DoSomethingElse();
}
And you have implemented the interface in your parent form:
public class Form1: Form, IDoSomething
{
// ...
public void DoSomething()
{
//Hide userControl11 and show userControl21
}
public void DoSomethingElse()
{
// ...
}
}
Then in you user control:
private void Button1_Click(object sender, EventArgs e)
{
var f = FindForm() as IDoSomething;
if(f!=null)
f.DoSomething();
}
回答2:
I want to expand on Reza Aghaei's answer a bit. I think it could get even better than it is now.
First way to do this
If I were you I would have some interface ICheckedView
which has at least 1 method to implement like so:
ICheckedView
{
void Continue();
}
Now, we're able to apply this interface to any class in our solution, most likely to views, though. Next, I would make your main form implement this interface and implement the required method. The in this case we want our main form to remove the control from the panel and add a new control. Frankly, our Safety check control doesn't need to (and maybe shouldn't) know about other controls or what happens next. It's just used for flow of control.
Finally, you need to add either a public property, or maybe even a parameter to the constructor for Safety_Check which includes an ICheckedView
in it. When your safety check control gets clicked it can tell whoever has been passed into it (we'll say the client) that it must continue.
Second way to do this
It can be done with an action delegate.
If you add an Action
delegate to your safety check, you could just pop in any method whose signature matches that delegate (void methodName()
). The constructor for your Safety_Check control should include an Action and that Action would get assigned to a private field of the class. Then when it's time to invoke, that action can be invoked directly.
Notes on this method
Because we're probably invoking from the UI thread in the first place, we're probably alright, but you need to think about thread safety here. The invoke required pattern can help you around this.
来源:https://stackoverflow.com/questions/55053527/switch-usercontrols-in-mainform-within-a-usercontrol-click-event