I have a program that has a parent form which then creates a child form. Upon clicking the updateButton within the child form, I want the searchButton within the parent form to fire.
However I get an error for protection reasons. I have tried setting everything Public just to see, still wont work for me.
Error 1 'SalesSystem.SystemForm.searchButton' is inaccessible due to
its protection level SalesSystem\UpdateForm.cs 111 20 SalesSystem
This is what I have so far.
Parent Code
namespace SalesSystem
{
public partial class SystemForm : Form
{
public SystemForm()
{
InitializeComponent();
}
protected void searchButton_Click(object sender, EventArgs e)
{
//search code
}
private void updateButton_Click(object sender, EventArgs e)
{
try
{
UpdateForm upForm = new UpdateForm(resultBox.SelectedItems[0].Text, dbdirec, dbfname);
upForm.ShowDialog(this);
}
catch (Exception)
{
//
}
}
}
Child Code
namespace SalesSystem
{
public partial class UpdateForm : Form
{
public UpdateForm(string selectedPerson, string dbdirec, string dbfname)
{
InitializeComponent();
}
private void updateButton_Click(object sender, EventArgs e)
{
//do stuff
SystemForm parent = (SystemForm)this.Owner;
parent.searchButton.PerformClick();
this.Close();
}
}
}
Your searchButton button control is set to private by default in WinForm. You've said you set everything to public but I assume you mean you've set everything in the code you've posted to public. There are a few ways to fix this. The direct fix would be to simply go to Visual Studio designer, select the button, and set its Modifier property to internal or public.
However, it seems you're closing your form straight after so I'd just have my parent form subscribe to the FormClosing event of the form.
UpdateForm upForm = new UpdateForm(resultBox.SelectedItems[0].Text, dbdirec, dbfname);
upForm.FormClosing += (s, o) =>
{
//your code for what the parent class should do
};
upForm.ShowDialog(this);
If you're not closing the form then you can create your own event handler that your parent form subscribes to.
You have 2 options:
create a public void search() method in your parent form. Then, instead of accessing the the button on the parent form and invoking its click event, you run the search code directly. The new method is not tied to a GUI element and accessing it from a different form is no problem.
The better solution is to create a delegate. A delegate is an execution target that will be assigned at run time. The parent form still has a public void search() method. And when it creates the child form, it will pass the name of that function as parameter. The child form has no knowledge about the parent form (as opposed to the first option where the child MUST know that there is a method called search()). When it is time to inform whoever created the child form, the delegate is called. This is a small example:
public partial class SystemForm : Form
{
public delegate void dSearch();
public SystemForm()
{
InitializeComponent();
}
protected void searchButton_Click(object sender, EventArgs e)
{
search();
}
private void search()
{
//search code
}
private void updateButton_Click(object sender, EventArgs e)
{
try
{
UpdateForm upForm = new UpdateForm(resultBox.SelectedItems[0].Text, dbdirec, dbfname, search);
upForm.ShowDialog(this);
}
catch (Exception)
{
//
}
}
}
And the child form:
public partial class UpdateForm : Form
{
private SystemForm.dSearch _target;
public UpdateForm(string selectedPerson, string dbdirec, string dbfname, SystemForm.dSearch target)
{
_target = target;
InitializeComponent();
}
private void updateButton_Click(object sender, EventArgs e)
{
//do stuff
_target();
this.Close();
}
}
You should use the "Model View Controller" or "Model View Presenter" pattern to approach this kind of thing.
Each form should only be concerned with displaying its contents to the user. When it comes to responding to UI events such as button clicks, each form (i.e. each "View") should simply raise an event which informs the controller/presenter that something has happened.
The controller/presenter should then respond appropriately. Then the logic that wires together different forms (such as the parent and child forms in your example) is encapsulated in the Controller class. Such logic does not really belong in either of the forms.
I wrote an example that demonstrates a simple design to do this sort of thing in another answer some time ago. Rather than copy/paste it all here, I'll just give you a link to it:
How to make Form1 label.text change when checkbox on form2 is checked?
You'll have to scroll down to see my answer. It's broadly similar to what you're doing; hopefully it will make sense to you! Follow the instructions to make a test application and run it to see what happens.
I'm tired and might be missing something but that is correct behaviour.
Your child form does not directly inherit from your parent form.
Your parent form has a protected level, so only it and classes that extend it can access the method.
2 solutions:
Change your child form to:
public partial class UpdateForm : SystemForm
Change method to public
public void searchButton_Click(object sender, EventArgs e)
You could expose a Search Event from your UpdateForm and subscribe to this event in the SystemForm
namespace SalesSystem
{
public partial class SystemForm : Form
{
public SystemForm()
{
InitializeComponent();
}
protected void searchButton_Click(object sender, EventArgs e)
{
//search code
}
private void updateButton_Click(object sender, EventArgs e)
{
try
{
UpdateForm upForm = new UpdateForm(resultBox.SelectedItems[0].Text, dbdirec, dbfname);
upForm.OnSearch += Search;
upForm.ShowDialog(this);
}
catch (Exception)
{
//
}
}
private void Search(string searchParameter)
{
....
}
}
namespace SalesSystem
{
public delegate void SearchEventHandler(string searchParameter);
public partial class UpdateForm : Form
{
public event SearchEventHandler OnSearch;
public UpdateForm(string selectedPerson, string dbdirec, string dbfname)
{
InitializeComponent();
}
private void updateButton_Click(object sender, EventArgs e)
{
//do stuff
OnSearch("SearchThis");
this.Close();
}
}
}
Related
I have a parent form that loads different user controls but when I am trying to access a method on the parent form from a button on the user controller which is not working but if the same method is accessed from the own parent form its all good I excluded the rest of code and here is the code not working
method on Parent Form:
using IT_HUB_MANAGEMENT_SOLUTION.SERVICES;
namespace IT_HUB_MANAGEMENT_SOLUTION.APP_FORMS
{
public partial class FIRST_RUN_FRM : Form
{
public FIRST_RUN_FRM()
{
InitializeComponent();
}
public void NEXT_STEP_CMD()
{
MAIN_PANEL.Controls.Clear();
FIRST_RUN_OBJECTS.CRYSTAL_REPORTS_CONTROL cRYSTAL_REPORTS_CONTROL = new();
cRYSTAL_REPORTS_CONTROL.Dock = DockStyle.Fill;
MAIN_PANEL.Controls.Add(cRYSTAL_REPORTS_CONTROL);
}
}
here is the code on user controls:
public partial class DOTNET_INSTALLER_CONTROL : UserControl
{
public DOTNET_INSTALLER_CONTROL()
{
InitializeComponent();
}
private void NEXT_BTN_Click(object sender, EventArgs e)
{
FIRST_RUN_FRM fff = new();
fff.NEXT_STEP_CMD();
}
}
First of all, this is not a normal behavior (at least for me) that a UserControl calls a parent form method directly. Usually user controls are not aware of the parent that is using them, and for me, it's a really smelly code.
In your code:
public partial class DOTNET_INSTALLER_CONTROL : UserControl
{
public DOTNET_INSTALLER_CONTROL()
{
InitializeComponent();
}
private void NEXT_BTN_Click(object sender, EventArgs e)
{
FIRST_RUN_FRM fff = new();
fff.NEXT_STEP_CMD();
}
}
You're simply creating a new instance of the FIRST_RUN_FORM (Also try to follow the naming convention) and then calling it's function. This won't throw a compiler error since it's a valid .Net syntax. You're creating a new class and calling a public function inside it. However, it won't show anything on your initial form because it's not the same instance.
There's two ways to fix this code, and I don't like the first way I'll show you.
You can add the parent form instance to the user control and pass it on when creating a new instance of the UC. Something like this:
public partial class DOTNET_INSTALLER_CONTROL : UserControl
{
private FIRST_RUN_FRM _parent = null;
public DOTNET_INSTALLER_CONTROL(FIRST_RUN_FRM parent)
{
InitializeComponent();
_parent = parent;
}
private void NEXT_BTN_Click(object sender, EventArgs e)
{
if (_parent == null)
{
return;
}
_parent.NEXT_STEP_CMD(); //This might throw an error not related to this question
}
}
I wouldn't recommend this though.
What I'd go for is using events, this way you don't need the UserControl to know who their parent is or what should be done to the parent when a button inside the UC is clicked.
Event:
In the user control:
public partial class DOTNET_INSTALLER_CONTROL : UserControl
{
public event EventHandler NextButtonClicked;
public DOTNET_INSTALLER_CONTROL(FIRST_RUN_FRM parent)
{
InitializeComponent();
_parent = parent;
}
private void NEXT_BTN_Click(object sender, EventArgs e)
{
OnNextButtonClicked();
}
protected virtual void OnNextButtonClicked()
{
EventHandler handler = NextButtonClicked;
handler?.Invoke(this, null);
}
}
And in the parent form you'll subscribe to this event and react when it's fired.
I am working with windowsFrom in c#. I am trying to call mainfrom method in one of the from in user control.
I have mainfrom like this
namespace Project
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
public void TempCommand()
{
StartTemp();
}
}
}
I have the button click in the user control. When i click that button then it will open another form. I have the code like this in the user control.
private TempCalib _tempCalib = new TempCalib();
private void calibBtn_Click(object sender, EventArgs e)
{
_tempCalib.Show();
}
it will open another from and i have one button in that from. I need to call mainfrom method when i click "Ok" button in this from.
namespace Project
{
public partial class TempCalib : Form
{
public TempCalib()
{
InitializeComponent();
}
private void OkButton_Click(object sender, EventArgs e)
{
// I need to call the mainfrom "TempCommand" method here.
this.Hide();
}
}
}
Can anyone help me how to do this.
Thanks.
Quick answer
Just add a reference to the primary form in your secondary form:
public partial class TempCalib : Form
{
private MainForm _main
public TempCalib(MainForm main) : this()
{
_main = main;
}
/// Other stuffs
}
Then assign value when you construct your secondary form:
private TempCalib _tempCalib;
private void calibBtn_Click(object sender, EventArgs e)
{
if (_tempCalib == null)
_tempCalib = new TempCalib(this);
_tempCalib.Show();
}
If calibBtn_Click isn't inside MainForm (but it's inside a UserControl on it) then you can replace _tempCalib initialization with:
_tempCalib = new TempCalib((MainWindow)FindForm());
You'll be then able to call the primary form:
private void OkButton_Click(object sender, EventArgs e)
{
_main.TempCommand();
this.Hide();
}
Notes: this is just one option, you may create a property to hold MainForm reference (so secondary form can be reused and it'll be more designer friendly) moreover TempCalib is not an UserControl but a Form (pretty raw but for an UserControl you may just check its parent Form and cast it to proper type).
Improvements
Such kind of references are often an alert. Usually UI components shouldn't not be so coupled and a public Form's method to perform something very often is the signal that you have too much logic in your Form. How to improve this?
1. DECOUPLE CONTROLS. Well a first step may be to decouple them a little bit, just add an event in TempCalib and make MainForm its receiver:
public partial class TempCalib : Form
{
public event EventHandler SomethingMustBeDone;
private void OkButton_Click(object sender, EventArgs e)
{
OnSomethingMustBeDone(EventArgs.Empty); / TO DO
this.Hide();
}
}
Then in MainForm:
private TempCalib _tempCalib;
private void calibBtn_Click(object sender, EventArgs e)
{
if (_tempCalib == null)
{
_tempCalib = new TempCalib();
_tempCalib.SomethingMustBeDone += _tempCalib_SomethingMustBeDone;
// In _tempCalib_SomethingMustBeDone you'll invoke proper member
// and possibly hide _tempCalib (remove it from OkButton_Click)
}
_tempCalib.Show();
}
2. DECOUPLE LOGIC FROM CONTROLS. UI changes pretty often, logic not (and when it changes probably isn't in parallel with UI). This is just the first step (now TempCalib isn't aware of who will use it). Next step (to be performed when too much things happen inside your form) is to remove this kind of logic from the form itself. Little example (very raw), keep TempCalib as before (with the event) and change MainForm to be passive:
public partial class MainForm : Form
{
public event EventHandler Calibrate;
protected virtual void OnCalibrate(EventArgs e)
{
// TODO
}
}
Now let's create a class to control the flow and logic:
public class MyTaskController
{
private MainForm _main;
private TempCalib _tempCalib;
public void Start()
{
_main = new MainForm();
_main.Calibrate += OnCalibrationRequested;
_main.Show(); // Or whatever else
}
private void OnCalibrationRequested(object sender, EventArgs e)
{
if (_tempCalib == null)
{
_tempCalib = new TempCalib();
_tempCalib.SomethingMustBeDone += OnSomethingMustBeDone();
}
_tempCalib.Show();
}
private OnSomethingMustBeDone(object sender, EventArgs e)
{
// Perform the task here then hide calibration window
_tempCalib.Hide();
}
}
Yes, you'll need to write much more code but this will decouple logic (what to do as response to an action, for example) from UI itself. When program grows up this will help you to change UI as needed keeping logic unaware of that (and in one well defined place). I don't even mention that this will allow you to use different resources (people) to write logic and UI (or to reuse logic for different UI, WinForms and WPF, for example). Anyway IMO the most obvious and well repaid benefit is...readability: you'll always know where logic is and where UI management is, no search, no confusion, no mistakes.
3. DECOUPLE LOGIC FROM IMPLEMENTATION. Again you have more steps to perform (when needed). Your controller is still aware of concrete types (MainForm and TempCalib). In case you need to select a different form at run-time (for example to have a complex interface and a simplified one or to use dependency injection) then you have to decouple controller using interfaces. Just an example:
public interface IUiWindow
{
void Show();
void Hide();
}
public interface IMainWindow : IUiWindow
{
event EventHandler Calibrate;
}
public interface ICalibrationWindow : IUiWindow
{
event EventHandler SomethingMustBeDone;
}
You could use a custom event that is declared in your UserControl. Then your form needs to handle this event and call the method you want to call. If you let the UserControl access your form, you are hard-linking both with each other which decreases reusability of your UserControl.
For example, in TempCalib:
public delegate void OkClickedHandler(object sender, EventArgs e);
public event OkClickedHandler OkClicked;
private void OkButton_Click(object sender, EventArgs e)
{
// Make sure someone is listening to event
if (OkClicked == null) return;
OkClicked(sender, e);
this.Hide();
}
in your mainform:
private void Mainform_Load(object sender, EventArgs e)
{
_tempCalib.OkClicked += CalibOkClicked;
}
private void CalibOkClicked(Object sender, EventArgs e)
{
StartTemp();
}
You create an event in your usercontrol and subscribe to this in the mainform.
That is the usual way.
Form1 Code:
UserControl1 myusercontrol = new UserControl1();
public void TabClose(Object sender,EventArgs e)
{
int i = 0;
i = tabControl1.SelectedIndex;
tabControl1.TabPages.RemoveAt(i);
}
private void Form1_Load(object sender, EventArgs e)
{
myusercontrol.Dock = DockStyle.Fill;
TabPage myTabPage = new TabPage();
myTabPage.Text = "Student";
myTabPage.Controls.Add(myusercontrol);
tabControl1.TabPages.Add(myTabPage);
myusercontrol.OkClick += TabClose;
}
UserControl1 Code:
public delegate void OkClickedHandler(Object sender, EventArgs e);
public partial class UserControl1 : UserControl
{
public event OkClickedHandler OkClick;
public UserControl1()
{
InitializeComponent();
}
private void button3_Click(object sender, EventArgs e)
{
if (OkClick == null) return;
OkClick(sender, e);
}
}
Try this:
From user control try this:
MainForm form = this.TopLevelControl as MainForm;
form.TempCommand();
I am creating a winforms application which uses Gmaps.net. I am unable to alter the order in which on Load methods are being called. For some reason the map_load is being called before the man_Load. Is there any way to change the order of this ?
If I can provide any more information to help just ask.
Thanks!
Dan.
public partial class main : Form
{
public main()
{
InitializeComponent();
}
private void main_Load(object sender, EventArgs e)
{
MessageBox.Show("main_load");
}
private void map_Load(object sender, EventArgs e)
{
MessageBox.Show("map_load");
}
}
It seems that you used the WinForms designer to create the map. The code behind is in the InitializeComponent() method and seems that the map is being loaded before the MainForm is loaded.
My recommendation is to create the map, once the MainForm has been loaded:
public partial class main : Form
{
public main()
{
InitializeComponent();
}
private void main_Load(object sender, EventArgs e)
{
Control map = CreateMap();
map.Docking = DockStyle.Fill;
this.Controls.Add(map);
}
private Control CreateMap()
{
// Create a new GMaps.NET object, intialize it and return
}
}
Hope it helps.
I have a UserControl, that contains a panel, the panel contains a picture box.
When I MouseMove over the Picture Box, I want to update a label on the MainForm.
I have a get/set method on the main form, but how do I use it?? thanks
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
public String MouseCords
{
get { return this.MouseCordsDisplayLabel.Text; }
set { this.MouseCordsDisplayLabel.Text = value; }
}
}
public partial class ScoreUserControl : UserControl
{
public ScoreUserControl()
{
InitializeComponent();
}
private void ScorePictureBox_MouseMove(object sender, MouseEventArgs e)
{
// MainForm.MouseCords("Hello"); //What goes here?
}
}
Actually it's possible to do in your case like:
((MainForm)this.ParentForm).MouseCords = "Some Value Here";
But the right way is with events like Felice Pollano mentinoed:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
this.myCustomControlInstanse.PicureBoxMouseMove += new EventHandler<StringEventArgs>(myCustomControlInstanse_PicureBoxMouseMove);
}
private void myCustomControlInstanse_PicureBoxMouseMove(object sender, StringEventArgs e)
{
this.MouseCordsDisplayLabel = e.Value // here is your value
}
}
public class StringEventArgs : EventArgs
{
public string Value { get; set; }
}
public partial class ScoreUserControl : UserControl
{
public event EventHandler<StringEventArgs> PicureBoxMouseMove;
public void OnPicureBoxMouseMove(String value)
{
if (this.PicureBoxMouseMove != null)
this.PicureBoxMouseMove(this, new StringEventArgs { Value = value });
}
public ScoreUserControl()
{
InitializeComponent();
}
private void ScorePictureBox_MouseMove(object sender, MouseEventArgs e)
{
this.OnPicureBoxMouseMove("Some Text Here");
}
}
Ideally, you should raise an event for the same.
Create a delegate
public delegate void Update();
in the user control
public class MyUserControl : UserControl
{
public event Update OnUpdate;
}
On the main form register a handler for the user controls event.
public class Main
{
public Main()
{
myUserControl.OnUpdate += new Update(this.UpdateHandler);
}
void UpdateHandler()
{
//you can set the delegate with sm arguments
//set a property here
}
}
On user control,
To raise an event on button click
do this
OnUpdate();
This might give you an idea...
public partial class ScoreUserControl : UserControl
{
public ScoreUserControl()
{
InitializeComponent();
}
private void ScorePictureBox_MouseMove(object sender, MouseEventArgs e)
{
// MainForm.MouseCords("Hello"); //What goes here?
MainForm parent = this.ParentForm as MainForm;
if (parent != null) parent.MouseCordsDisplayLabel.Text = "Hello";
}
}
You have several options:
Create an event on the user control and have to form listen to it (I think this is the recommended way by most C# programmers).
Pass a reference to the main form to the User Control (in the constructor). This way, the user control knows about its MainForm.
Cast this.ParentForm to the MainForm class, then you have the reference.
Options 2 and 3 are somewhat more comfortable and lazy, but the cost is that the user control has to know about the specific class MainForm. The first option has the advantage that you could reuse the user control in another project, because it does not know about the MainForm class.
You should publish an event from the user control and subscribe to it from the main form.
At least this is the pattern suggested for winform. In any case the idea is to make the control "observable" from the agents who need to see the coords, instead of using it as a driver to update the interested agents.
Hi I'm creating test application that has a user control with a Button that will be reference in a Form.
Is it possible to bind interface
public interface ICRUD
{
void Test();
}
to the user Control button1 click event
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//CALL ICRUD.Test() execute when click on form1 and then show I am Clicked
}
}
so that
i just need to implement only the interface functions to my form1.
Form1:
using System.Windows.Forms;
namespace TEST
{
public partial class Form1 : Form , ICRUD
{
public Form1()
{
InitializeComponent();
}
public void Test()
{
MessageBox.Show("I am Clicked");
}
}
}
Thanks in Regards.
This doesn't seems right to me. It's probably not the Form that should be implementing this interface. What's more, the interface doesn't bring anything here.
But if you really want to do that, you can access the ParentForm property, cast it to your interface and then call the method:
private void button1_Click(object sender, EventArgs e)
{
var crud = (ICrud)ParentForm;
crud.Test();
}
Also, the convention in .Net is to write abbreviations (at least the long ones) the same as other words, so you should name your interface ICrud.
private void button1_Click(object sender, EventArgs e)
{
for(var parent = this.Parent; parent != null; parent = parent.Parent)
{
var crud = parent as ICRUD;
if (crud != null)
{
crud.Test();
break;
}
}
}