c# Call List from one form into another - c#

first post of mine here and hoping to get a little bit of help for a problem i seem to can't figure out. For an assignment I am supposed to do, I need to create a game with 2 player attacking each other. I want the users to be able to upgrade their stats after each round, but upgrade them in a form separate from the game form (well call them UpgradeForm and GameForm, respectively).
I am keeping the majority of the players' data in class Helicopters in a List (List Heli = new List();) My biggest problem is trying to call that list from the GameForm into my UpgradeForm. Here is what I've got for code so far:
public partial class GameForm : Form
{
public List<Helicopter> Heli = new List<Helicopter>();
private void GameForm_Load(object sender, EventArgs e)
{
Heli.Add(new Helicopter(1, this));//give helicopter player # and set a form variable to the current GameForm
Heli.Add(new Helicopter(2, this));
}
private void GameForm_to_UpgradeForm()
{
newForm = true;
UpgradeForm UF = new UpgradeForm(this);
UF.Show();
FormProvider.GameForm.Hide();
//FormProvider is how i'm calling my GameForm.
//Shouldn't have an effect on what I'm trying to do.
}
}
In my UpgradeForm:
public partial class UpgradeForm : Form
{
private GameForm gF;
List<Helicopter> HeliList = new List<Helicopter>();
public UpgradeForm(GameForm gForm)
{
InitializeComponent();
this.gF = gForm;
HeliList = this.gF.Heli;
}
}
However, I get an error:
"Error 1 Inconsistent accessibility: field type 'System.Collections.Generic.List' is less accessible than field 'Project.GameForm.Heli'
What am i doing wrong, and what do i need to fix? Will post the code to FormProvider class if needed. Thanks in advance.

modifyyour UpgradeForm:
public partial class UpgradeForm : Form
{
private GameForm gF;
List<Helicopter> HeliList = new List<Helicopter>();
public UpgradeForm(List<Helicopter> list)
{
InitializeComponent();
HeliList.AddRange(list);
}
}
and from the GameFprm class:
private void GameForm_to_UpgradeForm()
{
newForm = true;
UpgradeForm UF = new UpgradeForm(Heli);
UF.Show();
FormProvider.GameForm.Hide();
}
"What am i doing wrong, and what do i need to fix?"
please don't pass an object of an ENTIRE form just for a list with 2 items
make your own classes and make instances of them without involving UI components

Related

Populate list in form from a table (Entity Framework) then use in other places in the form code

New C# and Entity Framework user. I want to put the results of a table into a C# list. I want to reference this list in multiple form events. I will cycle through the list from beginning to end throughout the life of the form.
Currently, I have this code (snippet):
public partial class FrmMain : Form
{
private readonly admEntities _admEntities = new admEntities();
public FrmMain()
{
InitializeComponent();
}
private void frmMain_Load(object sender, EventArgs e)
{
var exhibitor = _admEntities.Exhibitors.ToList();
// Put the first value in a text box - this works
txtCurrentSaleOrder.Text = exhibitor.First().SaleOrder.ToString();
}
}
I was hoping to use the exhibitor variable elsewhere on other events. However, I am unable to reference it.
I have not been successful in my searching and coding attempts to resolve this problem so far. Any pointer in the right direction would be appreciated.
One thing I tried was to put this code in a class above FrmMain(). That also failed. Probably due to not fully understanding classes yet.
You should make exhibitor a field, which is a fancy way of saying declare it outside of a method, inside of your class. Here is an example where exhibitor can be accessed from anywhere else in the class.
public partial class FrmMain : Form
{
private readonly admEntities _admEntities = new admEntities();
//It's unclear what exhibitor is in your question, so I'm using generic code that will allow it to work regardless.
private Type exhibitorType = typeof(admEntities.Exhibitors);
private List<exhibitorType> exhibitor = new List<exhibitorType>();
public FrmMain()
{
InitializeComponent();
}
private void frmMain_Load(object sender, EventArgs e)
{
//Can reference here
exhibitor = _admEntities.Exhibitors.ToList();
txtCurrentSaleOrder.Text = exhibitor.First().SaleOrder.ToString();
}
private void AnotherMethod()
{
//Can reference exhibitor here too.
}
}

Buttons don't work in Windows Forms C# by using classes

So, I'm currently working on a game library app, where you can add and organize games that are a part of your game library. So far I have three textboxes (one for game title, developer, and publisher), one checklistbox (to select which platform or system the game is on), three buttons ("Save Changes", "Add", and "Delete"), and finally a listview where the title of the game will be displayed whenever the user enters in the information and clicks the "Add" button. I was able to get it to work with no problems using the Form1.csclass, but figured it'd be best to organize the code using classes, which I've NEVER done with Windows Forms before (so I'm kinda a noob at this). For consistency reasons for this post, I made a saveAddDelete.csclass that has all my code for the "Save", "Add", and "Delete" buttons, which I transferred over from Form1.cs. I then call the saveAddDelete.csclass in Form1.csunder the designated button click events. There are no errors, but when I run the program, I enter in the information and click on the buttons, but they do nothing. So I think I'm either missing code or misunderstanding how classes work in Windows Forms. Here's the code below, and if anyone has any helpful feedback that would help me, I'd greatly appreciate it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GameLibrary
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public List<Library> Game = new List<Library>();
public Library lib = new Library();
public void saveBttn_Click(object sender, EventArgs e)
{
saveAddDelete save = new saveAddDelete();
save.Save();
}
private void button1_Click(object sender, EventArgs e)//Add Button
{
saveAddDelete add = new saveAddDelete();
add.Add();
}
private void deleteBtnClick_Click(object sender, EventArgs e)
{
saveAddDelete delete = new saveAddDelete();
delete.Delete();
}
public class Library
{
public string gametitle
{
get;
set;
}
public string developer
{
get;
set;
}
public string publisher
{
get;
set;
}
public string platform
{
get;
set;
}
}
class saveAddDelete
{
Form1 f = new Form1();
public void Save()
{
if(f.gameList.SelectedItems.Count == 1)
{
f.Game[f.gameList.SelectedItems[0].Index].gametitle = f.titleText.Text;
f.Game[f.gameList.SelectedItems[0].Index].developer = f.developerText.Text;
f.Game[f.gameList.SelectedItems[0].Index].publisher = f.publisherText.Text;
f.Game[f.gameList.SelectedItems[0].Index].platform = f.platformCheckBox.CheckedItems.ToString();
}
}
public void Add()
{
f.lib.gametitle = f.titleText.Text;
f.lib.developer = f.developerText.Text;
f.lib.publisher = f.publisherText.Text;
f.lib.platform = f.platformCheckBox.CheckedItems.ToString();
f.Game.Add(f.lib);
f.gameList.Items.Add(f.lib.gametitle);
f.titleText.Clear();
f.developerText.Clear();
f.publisherText.Clear();
foreach(int i in f.platformCheckBox.CheckedIndices)
{
f.platformCheckBox.SetItemCheckState(i, CheckState.Unchecked);
}
}
public void Delete()
{
Remove();
f.titleText.Clear();
f.developerText.Clear();
f.publisherText.Clear();
foreach (int i in f.platformCheckBox.CheckedIndices)
{
f.platformCheckBox.SetItemCheckState(i, CheckState.Unchecked);
}
}
void Remove()
{
try
{
f.gameList.Items.Remove(f.gameList.SelectedItems[0]);
f.Game.RemoveAt(f.gameList.SelectedItems[0].Index);
}
catch { }
}
}
Your helper class does not have reference to real form clicks are performed on (and hence do not get any values from the form).
One option - pass Form1 to each call instead of new'ing up Form1 in saveAndDelete class:
class saveAddDelete
{
// Form1 f = new Form1(); - delete that line
public void Save(Form1 f) {....} // pass Form1
and in each event handler pass this:
public void saveBttn_Click(object sender, EventArgs e)
{
saveAddDelete save = new saveAddDelete(this);
save.Save();
}
Note that you may consider using static methods for Save depending on your goals.
In your Form1 code, you create a new child object of type SaveAddDelete, but when you use the methods you created, you aren't passing any data into them. Instead, you are creating a new (empty) instance of Form1, which doesn't have any data to save or delete, and if you make any modifications to that new Form1, the original version of Form1 is not able to see those changes. You wind up with 2 different Form1's, neither of which know anything about the other one.
If you want to do it this way, you will need to pass a reference to the existing Form1 to the SaveAddDelete class:
public void saveBttn_Click(object sender, EventArgs e)
{
saveAddDelete save = new saveAddDelete();
save.Save(this);
}
and your SaveAddDelete methods will have to be expecting to receive an object of type Form1:
public void Save(Form1 f)
{
if(f.gameList.SelectedItems.Count == 1)
{
f.Game[f.gameList.SelectedItems[0].Index].gametitle = f.titleText.Text;
f.Game[f.gameList.SelectedItems[0].Index].developer = f.developerText.Text;
f.Game[f.gameList.SelectedItems[0].Index].publisher = f.publisherText.Text;
f.Game[f.gameList.SelectedItems[0].Index].platform = f.platformCheckBox.CheckedItems.ToString();
}
}
Notice that in the top sample, I pass "this" to the method, which is C# code for "whatever class is calling the code." In this case, "this" refers to your existing Form1 object. In the bottom sample, notice that the save method expects a Form1 object named "f" as a parameter. It does not create a new Form1 - it uses the one you pass to it.
For this example, I would actually just leave all of those methods in your Form1 class, since they are all related to the controls in Form1. New classes are generally used to model real-world objects - not to break out various pieces of code related to an existing class. Your "Library" class is a correct use of a separate class, since each instance of it represents a different game, and you have more than one of them that you need to keep track of separately (although I would call the class "Game" instead of "Library", since each instance of the class represents a single game, whereas the word library implies a collection of games.)

Control on another form is inaccessible due to it's protection level

TF2SelectDir.txtTF2DirSelect.Text = "";
This is giving me issues, as txtTF2DirSelect is on one form and I'm trying to change it from another. I tried looking it up, and the entire form itself is already public, not private.
Or, to go along with this, how can I create a variable that can be accessed on any form?
Where it goes wrong
if (canFindTF2 == true)
{
TF2SelectDir.txtTF2DirSelect.Text = "";
The form where TF2SelectDir is is already public
public partial class TF2SelectDir : Form
{
public TF2SelectDir()
{
InitializeComponent();
}
Any ideas? Thanks!!
UPDATE
At the bottom of my TF2SelectDir.Designer.cs, I've found
private System.Windows.Forms.TextBox txtTF2DirSelect;
private System.Windows.Forms.Button btnSaveTF2Dir;
private System.Windows.Forms.Label lblExample;
However, when I changed private to public on txtTF2DirSelect, I got a new error.
"An object reference is required for the non-static field, method, or property 'TF2SelectDir.txtTF2DirSelect' - Error Code CS0120
Since I cannot comment, I am posting this as an answer.
Accessing controls from a separate form, may not be the best idea. I would recommend you use properties. Here is Microsoft's definition and usage example of properties.
Another, even better way, in my opinion, to share data between two forms, is to use events. Once again, here is Microsoft's description of events.
If you need a working example of how to use either of these approaches, I would like to see your effort first and then we can build on that.
Expose control in below way .. why?? #monstertjie_za provided few good links on that already .
namespace TF2Overwatch
{
public partial class TF2SelectDir : Form
{
//Approch 1 - usable when the projects most works are done
//without following a good architecture
//You can use a static variable to preserve the state and intilize each time
//a new instance is created
//Approch 2 - Responibilty of preserving text to initlize in textbox should be taken
//by the form who calling this form
//value will pass by consturtor or by exposing property
//all approch 2 code are kept commented for better understanding
private static string strTxtTF2DirSelectTextToInitize;
public TF2SelectDir()
{
InitializeComponent();
txtTF2DirSelect.Text = strTxtTF2DirSelectTextToInitize;
}
public static string TxtTF2DirSelectTextToInitlize
{
get
{
return strTxtTF2DirSelectTextToInitize;
}
set
{
strTxtTF2DirSelectTextToInitize = value;
}
}
//public TF2SelectDir(string txtTF2DirSelectText)
//{
// InitializeComponent();
// txtTF2DirSelect.Text = txtTF2DirSelectText;
//}
//public string TxtTF2DirSelectTextToInitlize
//{
// get
// {
// return txtTF2DirSelect.Text;
// }
// set
// {
// txtTF2DirSelect.Text = value;
// }
//}
}
public partial class SomeAnotherForm:Form
{
public SomeAnotherForm ()
{
InitializeComponent();
}
protected void InSomeAction(object Sender, EventArgs e)
{
if (canFindTF2 == true)
{
TF2SelectDir.TxtTF2DirSelectText = "Test";
TF2SelectDir t1 = new TF2SelectDir();
t1.Show();
//Approch 2
//TF2SelectDir t1 = new TF2SelectDir("Test");
//t1.Show();
//TF2SelectDir t1 = new TF2SelectDir();
//t1.TxtTF2DirSelectText="Test"; //look here TxtTF2DirSelectText is setting on instance not by class
//t1.Show();
}
}
}
}

Modifying a winform textbox value from another class

I'm wondering if it is possible to access a textbox value from another class inside a C# winform.
For example, at the moment I have a bunch of different textboxes I'm turning on and off all within my Form1.cs class like so:
screentextBox.Visible = true;
However, to cut down on the amount of lines of code within my C# class I was wondering is it possible to make this call from another class, then in my Form1.cs call my other classes method?
Something like:
class Otherclass
{
public void ShowTextBox()
{
screentextBox.Visible = true;
}
}
Then in my Form1.cs simply call my new ShowTextBox method.
I'm sorry if this is a silly question, but I've looked around google and I couldn't find anything that could help me out.
You could pass the TextBox as a parameter to a function in another class:
class OtherClass
{
public void ShowTextBox(TextBox target)
{
target.Visible = true;
}
}
However, I would advise to keep all the methods and code pertaining to handling the GUI and its events inside the form itself. If you have large methods for calculations, etc., than those can be moved to other classes.
you can Make ScreentextBox as Public in Declaring class and access it in Another class like
class Otherclass
{
public void ShowTextBox()
{
Class1.ScreenTextBox.Visible =true;
}
}
You could define the ShowTextBox method in a partial class So you still have the access to the control and also tidy your code.
Add method for showing TextBox in your form:
public partial class Form1 : Form
{
public void ShowTextBox()
{
screentextBox.Visible = true;
}
}
and then pass your From1 to other forms and call this method from there.
Class OtherClass
{
public static void method(TextBox[] items)
{
foreach(item in items)
{
(item as TextBox).Visible = true;
}
}
}
to call this method from ur Form1.cs class--->
OtherClass.method( new TextBox[] { TxtBox1, TxtBox2, TxtBox3 } );
If you want to access the controls of Form1.cs from another class try this way
class Otherclass
{
Form1 f1 = new Form1();
f1.Controls["screentextBox"].Visible = true;
}
I would do it like this (example from John Willemse):
class OtherClass
{
public TextBox ShowTextBox(TextBox target)
{
target.Visible = true;
return target;
}
}
Yet another approach to this old problem: I've found that the old way is an easy way to make accessible controls (including all their properties and methods), and perhaps other variables, from any class within the project. This old way consists of creating an ad hoc class from scratch.
Note A: about the old way: I know, I know, global variables are evil. But, for many people coming here looking for a fast/flexible/suites-most-cases solution, this may be a valid answer and I have not seen it posted. Another thing: this solution is what I am actually using as the answer for what I came to this page looking for.
1st step: The new class file from scratch is below.
namespace YourProjectNamespace
{
public class dataGlobal
{
public System.Windows.Forms.TextBox txtConsole = null;
// Place here some other things you might want to use globally, e.g.:
public int auxInteger;
public string auxMessage;
public bool auxBinary;
// etc.
}
}
Note B: The class is not static nor has static members, which allows to create several instances in case it is needed. In my case I do take advantage of this feature. But, as a matter of fact, you may consider making this class' TextBox a public static field so that -once initialized- it is always the same throughout the application.
2nd step: Then you're able to initialize it in your Main Form:
namespace YourProjectNamespace
{
public partial class Form1 : Form
{
// Declare
public static dataGlobal dataMain = new dataGlobal();
public Form1()
{
InitializeComponent();
// Initialize
dataMain.txtConsole = textBox1;
}
// Your own Form1 code goes on...
}
}
3rd step: And from your other class (or form), the call to any property/method of Form1's textBox1:
namespace YourProjectNamespace
{
class SomeOtherClass
{
// Declare and Assign
dataGlobal dataLocal = Form1.dataMain;
public void SomethingToDo()
{
dataLocal.txtConsole.Visible = true;
dataLocal.txtConsole.Text = "Typing some text into Form1's TextBox1" + "\r\n";
dataLocal.txtConsole.AppendText("Adding text to Form1's TextBox1" + "\r\n");
string retrieveTextBoxValue = dataLocal.txtConsole.Text;
// Your own code continues...
}
}
}
[EDIT]:
A simpler approach, specifically for the TextBox visibility throughout classes, I have not seen in other answers:
1st step: Declare and initialize an auxiliary TextBox object in your Main Form:
namespace YourProjectNamespace
{
public partial class Form1 : Form
{
// Declare
public static TextBox txtConsole;
public Form1()
{
InitializeComponent();
// Initialize
txtConsole = textBox1;
}
// Your own Form1 code goes on...
}
}
2nd step: And from your other class (or form), the call to any property/method of Form1's textBox1:
namespace YourProjectNamespace
{
class SomeOtherClass
{
public void SomethingToDo()
{
Form1.txtConsole.Visible = true;
Form1.txtConsole.Text = "Typing some text into Form1's TextBox1" + "\r\n";
Form1.txtConsole.AppendText("Adding text to Form1's TextBox1" + "\r\n");
string retrieveTextBoxValue = Form1.txtConsole.Text;
// Your own code continues...
}
}
}
Comment to the [Edit]: I have noticed that many questions simply cannot be solved by the usual recommendation: "instead, make public properties on your form to get/set the values you are interested in". Sometimes there would be several properties/methods to implement... But, then again, I know... best practices should prevail :)

Problem creating instance of a class

I've create the following class in Visual Studio 2010:
public class Bat : Form1
{
public int BatLocation;
public void draw()
{
Pen batPen = new Pen(Color.Black);
batPen.Width = 10;
playArea.DrawRectangle(batPen, BatLocation, (picPlayArea.Height - 30), 50, 10);
}
}
But when I try to create an instance of the class, I get a stack overflow exception, advising me to make sure that I don't have an infinite loop or infinite recursion. I have tried creating the instance two different ways, as below:
Bat bottomBat;
bottomBat = new Bat();
and
Bat bottomBat = new Bat();
But both ways return the same error when I try to run the program. I've also tried the class definition with and without the public modifier.
I'm pretty new to programming and have no idea what might be causing this problem. Am I doing something wrong?
Edit: The code for the Bat class is everything I have at the moment, haven't created a specific constructor for it... Didn't think I needed to?
Anyway, here is the Form1 class in its entirety:
public partial class Form1 : Form
{
// Define various objects for the game
public Graphics playArea;
Bat bottomBat = new Bat();
public Form1()
{
InitializeComponent();
// Create instances of objects
playArea = picPlayArea.CreateGraphics();
//bottomBat = new Bat();
// Delegate the mouseMove event for picPlayArea
picPlayArea.MouseMove += new MouseEventHandler(picPlayArea_MouseMove);
}
private void picPlayArea_MouseMove(object sender, MouseEventArgs e)
{
bottomBat.Location = e.X;
}
private void btnExit_Click(object sender, EventArgs e)
{
string msg = "Are you sure you want to exit?",
title = "Confirm Exit";
DialogResult res = MessageBox.Show(msg, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (res == DialogResult.Yes)
{
Environment.Exit(0);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
// This is where most of the functionality is executed within the game
playArea.Clear(Color.White);
}
private void btnStart_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
}
}
It appears you have combined inheritance and composition in an impossible sort of way. The base Form1 type has a field declared to be of the derived Bat type. In addition, it uses a field-initializer to initialize it to a new instance of that type. Clearly, you have a turtles-all-the-way-down issue: when you create a Bat (or a Form1 for that matter), the field-initializer will run - this will create an instance of another Bat, which in turn will create yet another Bat, and so on, ad-infinitum in theory. (in practice: until you run out of stack-space).
Here's a simple fix that should solve the stack-overflow issue, but may not be the most appropriate design in the 'big-picture':
public class Bat
{
public void Draw(Graphics playArea)
{
...
}
}
Notice how this type no longer subclasses Form1; it inherits directly from System.Object. Now neither the Form1 nor the Bat classes will exhibit infinite recursion when instances of them are created.
It's hard to suggest the best fix without knowing the ultimate aim here. I suggest you give some thought to the best way to design these classes. I would think you need to spend some time learning about the C# programming language, OO design, as well as WinForms specifics. I think you're actually looking to override the OnPaint virtual method here.
Often the cause is confusing a property with its backing variable.
Something along the lines of:
public class tmp
{
private int _x;
...
public int X(x)
{
X = x;
}
You have a simple problem.
your class Bat is derived from Form1, and in Form1 you create a new instance of Bat, which in turn is based on Form1 so that creates a new instance of Bat.... and so it repeats until your stack space is used up.
In general, Form1 probably should not know about the class Bat, and that all code that needs to know about Bat should be in the Bat class. However, in exceptional circumstances, you can solve this issue like this:
partial class Form1
{
public Form1(Bat _bat)
{
mBat = _Bat;
}
protected Bat mBat;
}
and on the Bat class
public class Bat : Form1
{
public Bat() : base(this)
{
}
}

Categories