Passing information between panels and classes - c#

My application (namespace) has a master form (Form) that contains a panel (panel).
When the master form loads, it calls a subform into it's panel. That subform acts as a splash page. It has a "launch" button on it. When the button is clicked, the subform should hide and a new form should load into the panel.
private void buttonLaunch_Click(object sender, EventArgs e)
{
this.Hide();
Hub NewHub = new Hub();
NewHub.TopLevel = false;
NewHub.AutoScroll = true;
Master.panelMaster.Controls.Clear();
Master.panelMaster.Controls.Add(NewHub);
NewHub.FormBorderStyle = FormBorderStyle.None;
NewHub.Show();
}
I'm getting the error:
Error 1 An object reference is required for the non-static field, method, or property 'Manager_0._2.Master.panelMaster'
I'm not sure how to interpret the error to resolve the issue.

Okay, assuming you have a class called namespace.class that contains a member named panel, the compiler is telling you that you seem to be trying to access panel via the class itself rather than an instance of the class (i.e. an object). To make an instance of class, do something like this:
namespace.class c = new namespace.class();
Then you can access the property or field named panel on that object:
c.panel.Controls.Clear();
Note: your naming choices are very poor. Calling a namespace namespace or a class class is just asking for trouble. Here are some recommended naming conventions:
Naming Guidelines
Update: from a closer read of your question, it appears that you're trying to add a Form to a Panel. Once you get past this compilation issue, you're going to start getting runtime errors, because that's just not how Windows Forms works. You can't put a Form in a Panel. Forms are top-level UI elements. I honestly don't understand your goals here well enough to suggest what to do instead.

Related

Pass form to another class and extract controls and properties

This is more so a general question than an issue I have. I have a form with 30+ controls that I will use to populate a model, which eventually ends up in a database.
I was wondering, however, if I could just pass the whole form object to another class, and pull the contents out in the other class without setting up a whole bunch of getters and setters.
Let's say I have a form Form1, and I make this call:
OtherClass.Validate(this)
Then, in the OtherClass (which is in a different project in the same solution) I have:
public static void Validate(Form1 myForm)
I have played around with this a little. In the Validate() method, if I put a watch on myForm, I can see all the form controls and properties, but I don't know if there is a way to just pull them out. If I type myForm., intellisense shows me all the standard form methods and properties, but not the controls and properties specific to the form. Has anybody tried this successfully?
You may grab controls from a form object using
myForm.Controls
This gives you a collection of controls within the form. You may iterate through them with a foreach loop.
Example with this form containing two buttons. You may use the following code to get the controls text.
public static void Validate(Form1 myForm)
{
foreach (Control control in myForm.Controls)
{
string text = control.Text;
Console.WriteLine(text);
}
}
Triggering the above function prints the following to the console. (Using this form)
button2
button1
This method works for TextBox and other controls too. However, it may be trickier if you have controls within controls. You may solve that by making a recursive function.
Each control on a form has a property called "Modifiers":
It is "Private" by default (for a reason: UI is the most likely subject for changes, any logic outside the form should not depend on controls. One control can be replaced with another, a group of controls can be replaced with a custom control. When controls are public, such change is not incapsulated and triggers changes in many parts of the system)
Controls which are added on a form, are serialized into C# code in form.designer.cs file. Code for textBox1, when it has modifier Private:
private System.Windows.Forms.TextBox textBox1;
Change it to Public like shown on a screenshot, and it will become
public System.Windows.Forms.TextBox textBox1;
Public controls will be accessible like any other public fields:
public static void Validate(Form1 myForm)
{
if (String.IsNullOrEmpty(myForm.textBox1.text))
{
// do smth about empty field
}
}

Calling a public method from another class doesn't respond

I'm making a game library with C#.
I have a main Form which has a FlowLayoutPanel, which hosts the game library. There is an "add game" method in main Form which adds an item to FlowLayoutPanel, but this method is being called from a second form. But when I'm calling this method from this second form, nothing happens at all, but it works, if called from the main form.
Here's the code:
Here's the add game method in mainForm:
public void addIso()
{
PictureBox gameBox = new PictureBox();
gameBox.ImageLocation = "link here";
gameBox.Height = 200;
gameBox.Width = 150;
gameBox.SizeMode = PictureBoxSizeMode.StretchImage;
isoPanel.Controls.Add(gameBox);
}
This method adds a placeholder game to FlowLayoutPanel called isoPanel. Works when called from the same form.
And here's how the method is being called from second form:
private void addGameButton_Click(object sender, EventArgs e)
{
MainWindow mainForm = new MainWindow();
mainForm.addIso();
}
When I tried to add simple message box in the method, message box did show, but game wasn't added to FlowLayoutPanel.
Any tips or solutions?
I apologize for my poor english and messy programming terms, I started learning C# a little while ago.
You can achieve this by using delegate and Delegate.
What you are doing wrong here:
From addGameButton click event you are creating a new instance of the mainForm. Which is not the actual main form that you are currently seeing, its a different instance of the mainForm. your code adds the control to the layout just confirm this by calling mainForm.Show() this will opens a new form with the control.
What you can do:
In such cases, you want to modify the parent control, calling methods in parent class, you need to use delegates by the following way:
Changes needs to apply in the Parent class ie., MainWindow.
Define a delegate and an event of that delegate type.
public delegate void UpdateUiDelegate();
public event UpdateUiDelegate UpdateUiEvent;
Assign the required method to the Event(better use this in constructor):
public MainWindow ()
{
UpdateUiEvent+= new UpdateUiDelegate(addIso);
}
Next work is in the child form ie., Form2 (use a better name let it be ImageChildControl). Create a Delegate there:
public Delegate ControlCreator;
Come back to MainWindow, Locate the place where you are calling the Second form, after creating instance of the child form assign the created event to that Delegate of the instance, for that Use the following codes there:
ImageChildControl ImageChildControlInstance = new ImageChildControl();
ImageChildControlInstance.ControlCreator = UpdateUiEvent;
One more work to do in child form that is; Calling the delegate from the Button click event. ie.,
private void addGameButton_Click(object sender, EventArgs e)
{
ControlCreator.DynamicInvoke();
}
Now you can see your code works as you expected.
You seem to be recreating the form when you load the second form.
as this does lack a little context.
I suggest you have a main tread which will run the two forms
create a game manager class Ex: GameManager.cs
In the class create a variable for both forms and set them as protected.
in each form send a reference of the gamemanager to it.
which will allow each window to communicate with each other through the manager by provide secure inter communication.
Let me know if you would like some source with this.

Why can't I access a textbox on another form?

Another beginners question here, coming from Delphi you always have access to another forms controls but in my early days with C# / Visual Studio I am faced with a problem which is proving more difficult than it should be.
I have been getting started by writing a simple notepad style application, I have my main form and a secondary form used to select a line number.
From my main form, I call the goto line number form like so:
private void mnuGoTo_Click(object sender, EventArgs e)
{
Form gotoForm = new GoToForm();
var dialogResult = gotoForm.ShowDialog();
if (dialogResult == DialogResult.OK)
{
// get the text from gotoForm.editLineNumber.Text
MessageBox.Show(gotoForm.editLineNumber.Text); // doesn't work
}
}
As you can see from the commented code I have a TextBox control called editLineNumber which is on my other form (GoToForm).
My problem (and likely a beginner question) is why does editLineNumber not show in the intellisense menu when I type gotoForm.?
How do I access the editLineNumber control from the form GoToForm?
The error message for the // doesn't work commented line is:
Error CS1061 'Form' does not contain a definition for 'editLineNumber'
and no extension method 'editLineNumber' accepting a first argument of
type 'Form' could be found (are you missing a using directive or an
assembly reference?)
Unless I am missing something obvious, why are controls that exist on another form not publically available to all forms? I understand that C# / Visual Studio is different to Delphi but the way Delphi lets you access and see all controls on all forms without any extra works seems more logical to me. Why does C# / Visual Studio hide controls on secondary forms, for what purpose can this be beneficial?
The editLineNumber control is private. You can change it to be public, but that's discouraged.
Instead, create a property in GoToForm that returns the value you want.
public string LineNumber
{
get { return this.editLineNumber.Text; }
}
Now you can just reference your new property:
if (dialogResult == DialogResult.OK)
{
MessageBox.Show(gotoForm.LineNumber);
}
Especially if you're new to C# and WinForms, don't touch designer code with a 10 foot pole. As Grant Winney said, use a property:
public string GetLineNumberText
{
get { return this.editLineNumber.Text; }
}
It should be mentioned that it's important to be aware of the directional nature of forms. That is to say, if I make Form1 and then define Form2 inside of it, you'll want to be careful how you communicate between the two forms. Properties are nearly always a better alternative than accessing form elements directly - it makes the code very difficult to change otherwise. If you, for example, removed editLineNumber from the other form or renamed it, every instance in the parent form would have to be edited. If you use a property, then you only have to change it in one place.

C# Windows Forms: Access Controls(Labels, Buttons) in other Classes

I need to know, how I can access lables or buttons other than in my "Form1"-Class.
My Problem:
I created for example labels, buttons via the design viewer. Now I can access
them in my Form1 Class. (testlabel.Enabled == true) just for example.
What I CAN'T do: Access those labels, buttons in another class! Let's say
I have a class "second-class" and I want to have a method there, that changes
the property of a label to
`testlabel.Enabled == false`
That's not possible, because in that "second-class" it's not visible.
So, is there an obvious easy solution to make those controls accessible in other classes?
Create a method in that (Second class) which takes that component (Label or Button or whatever you want to modify) as parameter into that method.
public void disableLabel(Label inputLabel)
{
inputLabel.Enabled == false
}
Create a method like the above.
Now in the form1 class you just to need to call that method and pass your Label into that method to Disable it.
SecondClass objSecondClass = new SecondClass();
objSecondClass.disableLabel(testlabel);
Every control in a form class is created by default with its property Modifiers set to Private
If you change it to Public you could access the control instance from another class.
However this is really a bad practice to follow. Messing with the visibility of the control is dangerous and could cause very complicated bugs to resolve.
If you really need to change something in your form class then provide a public method and call this method to change the internal functionality of the target form

C# Using a form to load other user controls and have access to a base control or property

Currently I have a C# program with a windows form and then a user control template put onto the form. The user control template is really just used as a placeholder. I have a series of other controls which inherit from this user control template.
Each of those controls have navigation buttons like 'Continue' and 'Back' on them and each control knows which control needs to be loaded next. However what I need to figure out is an easier way to have variables that are global to these controls.
The only workaround I have is that I pass the form to each control when they are loaded and use variables inside of the form to read and write to. What would be the proper way to have each of these user control screens be built off of a base control which contained objects all of the controls could get to?
Sorry for the rambling nature of the post but I've been thinking about this problem all morning.
Here is some of the code:
Most of what I have written was based on hiding and showing the user controls so that content in the controls wouldn't be lost during navigation. I won't be needing to do that as eventually it will be loading the fields of data from a database.
Code for initially loading control from form click:
conTemplate1.Controls.Clear();
conInbound Inbound = new conInbound(this);
Inbound.Dock = DockStyle.Fill;
Inbound.Anchor = (AnchorStyles.Left | AnchorStyles.Top);
conTemplate1.Controls.Add(Inbound);
Code for Continue button inside of one of the controls:
if ((Parent.Controls.Count - 1) <= Parent.Controls.IndexOf(this))
{
UserControl nextControl = new conPartialClear();
nextControl.Dock = DockStyle.Fill;
Parent.Controls.Add(nextControl);
this.Hide();
Parent.Controls[Parent.Controls.IndexOf(this) + 1].Show();
}
else
{
this.Hide();
Parent.Controls[Parent.Controls.IndexOf(this) + 1].Show();
}
The best-practice for communicating from a control to a parent is to use events, and for communicating from a parent to a control is to call methods.
However, if you don't want to or can't follow this practice, here's what I would recommend.
Each UserControl has a ParentForm property that returns the Form that contains the control. If you know that the UserControl will always be attached to MyParentForm, you just cast the ParentForm and then you can access all public controls, methods, etc.
Here's what I mean:
public class conTemplate
{
public MyParentForm MyParentForm
{
get
{
return (MyParentForm)this.ParentForm;
}
}
}
This way, you can easily access any public members of MyParentForm. Your conInbound class could have code such as this.MyParentForm.GlobalSettings.etc..., and could even have access to any public controls.
I'm not totally sure I understand your problem. It sounds like you want the user control to "do something" with it's parent form. If that's the case, you may want to consider adding events to the UC and then handle them on the form itself.
Basically, for your UC's "continue", you'll have an event that's fired when it's pressed. You'll want to handle that in your form. I'm not real sure about the syntax from memory, or I'd work something out for you code-wise. But I think that's the route you'll want to take. Think of your UC like any other windows form control. If you add a button to your form, you assign it it's event method. Do the same with the UC.
I found this and thought it may be helpful. Scroll down to where it talks about UC's and events.
http://www.akadia.com/services/dotnet_user_controls.html
Hope this helps.
EDIT after new info from OP.
You could declare a global variable inside the UC of type yourForm and then set that variable to the ParentForm at run-time, if I'm understanding you correctly.
So, inside your UC Class, you could do:
private parentFormInstance;
then inside the constructor of the UC, you could set it as such:
parentFormInstance = this.ParentForm; (or whatever the property name is).
This allows you at design-time to use:
parentFormInstance.DoSomething();
without the compiler yelling at you.
Just basic advice, but if you can go back and make it easier on yourself, even if it takes some additional time re-working things, it'd be worth it. It may save you time in the long run.

Categories