Access objects instantiated by sibling control - c#

Being fairly new to C# and OOP I'm having some newbie problems with scope and access, one of them being this: When the main form loads an instance of the class Doc is created and the constructor opens a Word document and creates a list of all the images in the document. The first image in the list is displayed in a picturebox, like so:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
public class Doc {
public List<Image> images = new List<Image>();
public Doc(string path) {
// Open Word document, create list of images
}
}
private void Form1_Load(object sender, EventArgs e) {
Doc doc = new Doc("C:\\lorem_ipsum.doc");
pictureBox1.Image = doc.images[0];
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e) {
pictureBox1.Image = doc.images[numericUpDown1.Value];
}
}
There is also a numericUpDown control which should be used to display different images, and that's where the problem is. The last block of code in the example above doesn't work, but I hope it illustrates what I want to do.
What would be a best practice solution to this problem (and similar ones where one control should be able to access objects created by other controls)? I have also tried to solve it by creating a method for the Doc class but had problems accessing the picturebox from there instead.

Your problem is you created doc as a local variable. You need a member variable within the scope of the class:
public partial class Form1 : Form {
private Doc _doc; // Add this line
public Form1() {
InitializeComponent();
}
public class Doc {
public List<Image> images = new List<Image>();
public Doc(string path) {
// Open Word document, create list of images
}
}
private void Form1_Load(object sender, EventArgs e) {
_doc = new Doc("C:\\lorem_ipsum.doc");
pictureBox1.Image = _doc.images[0];
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e) {
pictureBox1.Image = _doc.images[numericUpDown1.Value];
}
}
A little about scope
public class MyClass
{
// myMemberVariable is declared inside class, but outside
// a function. Therefore, it can be accessed from anywhere
// inside the class.
int myMemberVariable;
public void MyFunction()
{
// myLocalVariable is declared inside a function. Therefore,
// it can be accessed only inside this function and nowhere
// else.
int myLocalVariable;
for (int x=0;x<10;x++)
{
// anotherLocalVariable is declared inside a for loop. Therefore,
// this variable can only be used inside this for loop and
// no where else.
int anotherLocalVariable;
}
}
}
Think of the braces as scope delimiters. Variables you create can only be used within the opening and closing braces and never outside. The only "partial" exception to this would be static variables.

Just make doc a private field of Form1.
public partial class Form1 : Form {
private Doc doc;
public Form1() {
InitializeComponent();
}
public class Doc {
public List<Image> images = new List<Image>();
public Doc(string path) {
// Open Word document, create list of images
}
}
private void Form1_Load(object sender, EventArgs e) {
doc = new Doc("C:\\lorem_ipsum.doc");
pictureBox1.Image = dok.images[0];
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e) {
pictureBox1.Image = doc.images[numericUpDown1.Value];
}
}

The doc you have there is a local variable, i.e. it's local to Form1_Load. That means it only exists inside that method. What you want is a member field, defined on the Form1 class itself. That will stick around as long as the form exists:
public partial class Form1 : Form
{
private Doc m_Doc;
....
private void Form1_Load(object sender, EventArgs e)
{
m_Doc = new Doc("C:\\lorem_ipsum.doc");
pictureBox1.Image = m_Doc.images[0];
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
pictureBox1.Image = m_Doc.images[numericUpDown1.Value];
}
}
Now m_Doc will be accessible to anything in the class (and to nested classes as well), but nothing else, since it's private.
I've also chosen to add a m_ suffix. It is not necessary and people will argue about what convention is best all night long, but that's what I prefer!

Related

How to save and open the content in the one of subforms separately?

There are two forms, a MainForm and a GraphicsForm.
In MainForm, there are "New" and "Save", "Open" buttons. When clicking the "New", a GraphicsForm created (When the "New" is clicked multiple times, multiple GraphicsForms are created).
The question is, when created multiple GraphicsForms, and the user only wants to save the content in one of them or open a content file to one of them, How to implement this?
MainForm.cs
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private ToolStripMenuItem _winMenuItem = new ToolStripMenuItem();
private GraphicsForm _graphicsForm;
private int _counter = 1;
private ContentDoc _contentDoc = new ContentDoc();
private void New_Click(objec sender, EventArgs e)
{
_winMenuItem.Name = "Win";
_winMenuItem.Text = "Windows";
int item = MainMenuStrip.Items.IndexOf(_winMenuItem);
if (item == -1)
{
MainMenuStrip.Items.Add(_winMenuItem);
MainMenuStrip.MdiWindowListItem = _winMenuItem;
}
_graphicsForm = new GraphicsForm(_contentDoc);
_graphicsForm.Name = string.Concat("Win_", _counter.ToString());
_graphicsForm.Text = _graphicsForm.Name;
_graphicsForm.MdiParent = this;
_graphicsForm.Show();
_graphicsForm.WindowState = FormWindowState.Maximized;
_counter++;
}
private void Save_Click(object sender, EventArgs e)
{
... // here
}
private void Open_Click(object sender, EventArgs e)
{
... // here
}
}
GraphicsForm.cs
public partial class GraphicsForm : Form
{
//ContentDoc is a class to manage all the graphics drawn by the user in the form.
private ContentDoc _contentDoc = new ContentDoc();
public GraphicsForm(ContentDoc contentDoc)
{
InitializeComponent();
_contentDoc = contentDoc;
}
private Canvas_MouseDown()
{
}
private Canvas_Paint()
{
}
...
The parent form has an ActiveMdiChild property, so you can use the to access the currently-selected GraphicsForm instance:
var activeGraphicsForm = ActiveMdiChild as GraphicsForm;
There are other variations you might use, e.g. pattern matching, depending on the specific details and your preference.
You can then put your saving logic in a public method in GraphicsForm and call it from the parent form. Alternatively, you can put your saving logic in the parent form and expose the data to be saved via one or more public properties in GraphicsForm.

Does not exist in current context (Visual C#)

I have an error coming up saying; The name 'map' does not exist in current context. What am I doing wrong?
Sorry I am quite new to coding...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
variables();
}
public static void variables()
{
string[,] map;
map = new string[140, 140];
}
public static void updateMap(string[,] map)
{
MessageBox.Show("a");
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
updateMap(map);
}
}
Create class variable string[,] map.
public partial class Form1 : Form
{
public string[,] map;
...
so your variable "map" will be accessible in all(non-static) methods of this class
Get rid of your variable method.
public static void variables()
{
string[,] map;
map = new string[140, 140];
}
instead, keep it inside your class, so all the other methods may access it.
Think of the class as the parent. All the "methods" inside the class are its children. Everything inside of the children are its "things". Children don't like to share, specially with their brothers or sisters.
That being the case you want it somewhere where the parent has control of it, and the children have to follow the parent's rules of "sharing"
Like this.
public partial class Form1 : Form
{
public string[,] map;
map = new string[140, 140];
public Form 1: Form1()
{
....
}
private void Form1_Load()
{
.....
}
public static void updateMap()
{
.....
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
.....
}
}
the variable map is only valid in this method because it is declared within:
public static void variables()
{
string[,] map;
map = new string[140, 140];
}
If it should be valid for the whole class, just declare it as a field:
public partial class Form1 : Form
{
string[,] map;
public Form1()
{
InitializeComponent();
}
...
}
But this is very, very basic. I highly recommend to read a book about C#:
http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=c%23
You have only declared map inside the context of the variables method (not sure what this method is even for). As a result, this variable is not accessible anywhere outside of that method. You need to declare it as a class property, like so:
public partial class Form1 : Form
{
private string[,] map;
...
}
Then, initialize this on your Load method:
private void Form1_Load(object sender, EventArgs e)
{
map = new string[140,140];
}
You can then do away with the variables method and reference this property from inside your other methods as you are doing now.

Call Class Method from other Class not working

I'm trying to call methods from class "Form1" from an other class.
Here's my Code
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
MessageBox.Show("loaded");
orders.ObjectForScripting = new ScriptInterface();
}
private void webBrowser2_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { }
private void button1_Click_1(object sender, EventArgs e) { }
}
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class ScriptInterface
{
public void callMe(string currid)
{
MessageBox.Show(currid);
// the following throws security error
Form1.webBrowser2.Navigate("http://www.mywebpage.com/client/index.php?id="+currid);
}
}
}
INFO: I have 2 WebBorwsers. I'm catching events from webBrowser1 for updating webBrowser2.
My problem is, that i cannot call the webbrowser2 methods outside from Form1.
Any Ideas how i can solve this problem?
Your WebBrowser components are not static (this is a good thing), therefore you cannot refer to them directly off of Form1 as your code sample is attempting to do. You must obtain a reference to a Form1 instance and then you can call methods on them so long as they are marked public. Depending on your needs it is probably even better to just pass along a reference directly to your WebBrowser components
Perhaps something like this:
orders.ObjectForScripting = new ScriptInterface(this.webBrowser2);
...
public class ScriptInterface
{
private WebBrowser _browser;
public ScriptInterface(WebBrowser browser)
{
_browser = browser;
}
public void callMe(string currid)
{
_browser.Navigate("http://www.mywebpage.com/client/index.php?id="+currid);
}
}
Form1 in:
Form1.webBrowser2.Navigate(...)
Is not an object, but it is your type. You need to create an instance of your class, or if you prefer, create an object to be able to call it's method:
Form1 form = new Form1();
form.webBrowser2.Navigate(...)
On top, your method are flagged private, which mean they can only be call from inside your instanced. You should flag them public if you want other object to be able to call them.
public void webBrowser2_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { ... }
Or if you don't want to create an instance, you can declare this method as being static
public static void webBrowser2_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { ... }
But you won't be able to access the fields that this class define unless they are static too.

Accessing Form's Control from another class C#

I'm a newbie in c# and visual studio, but not programming in general.
I searched for answer to my question for 3 days and I found plenty of them, but for some weird reason (I'm sure I'm missing something very obvious) I cannot get it to work.
I think it's the most basic question newbies like me ask.
I have a form (Form3) with a text box and a button (I set it up is just for testing purposes).
I want to populate and read this text box from another class. I understand the most proper way to do this is to create a property in Form3.cs with GET and SET accessors. I did that but I cannot get it to work. I'm not getting any error messages, but I'm not able to set the value of the text box either. It just remains blank.
Here's my sample code:
namespace WindowsFormsApplication1
{
public partial class Form3 : Form
{
public string setCodes
{
get { return test1.Text; }
set { test1.Text = value; }
}
public Form3()
{
InitializeComponent();
}
private void Form3_Load(object sender, EventArgs e)
{ }
private void button1_Click(object sender, EventArgs e)
{
a.b();
}
}
public class a
{
public static void b()
{
Form3 v = new Form3();
v.setCodes = "abc123";
}
}
}
Can someone lend me a hand solving this?
The problem is you are setting the value to a new instance of the form. Try something like this:
public partial class Form3 : Form {
public string setCodes
{
get { return test1.Text; }
set { test1.Text = value; }
}
private A a;
public Form3()
{
InitializeComponent();
a = new A(this);
}
private void button1_Click(object sender, EventArgs e)
{
a.b();
}
private void Form3_Load(object sender, EventArgs e)
{
}
}
public class A
{
private Form3 v;
public a(Form3 v)
{
this.v = v;
}
public void b()
{
v.setCodes = "abc123";
}
}
You're creating a brand new Form3() instance.
This does not affect the existing form.
You need to pass the form as a parameter to the method.
Try this:
public partial class Form3 : Form
{
/* Code from question unchanged until `button1_Click` */
private void button1_Click(object sender, EventArgs e)
{
a.b(this);
}
}
public class a
{
public static void b(Form3 form3)
{
form3.setCodes = "abc123";
}
}
This passes the current instance of the form to the other class so that it can update the setCodes property. Previously you were creating a new form instance rather than updating the current form.
Sending form instance to other other class
Form1 objForm1=new Form1();
obj.Validate(objForm1);
Easy way to access controls in another class by modifying Controls Private to Public in the Form(Designer.cs)

call variable from another form C#

I have a DataGridView in Form1 and I'm using this code to display another form called Generator:
private void button1_Click(object sender, EventArgs e)
{
Form gen = new Generator();
// Form gen = new Generator(Form this); //* I tried this but is not working *//
gen.Show();
}
In the Generator form I need to read or modify something in the datagridview which is in the Form1.
public partial class Generator : Form
{
public Form myForm;
public Generator()
{
InitializeComponent();
}
public Generator(Form frm)
{
myForm = frm;
}
private void button1_Click(object sender, EventArgs e)
{
myForm.mydatagridview.! // this is not working
}
}
How can I resolve this problem, so I can manipulate the DataGridView from the Generator form?
Form 1:
private void button1_Click(object sender, EventArgs e)
{
Form gen = new Generator(this.mydatagridview);
gen.Show();
}
Generator Form:
DataGridView _dataGridView;
public Generator(DataGridView dataGridView)
{
InitializeComponent();
this._dataGridView = dataGridView;
}
private void button1_Click(object sender, EventArgs e)
{
this._dataGridView...! // this will work
}
Things that you must do, and know (just tips, you are not forced to do these but I believe you will be a better programmer if you do! ;)
Always call InitializeComponent() in all form constructors. In your sample you didn't call it in one of the constructors.
C# knows only information of the type you have passed. If you pass a Form, then you only get Form properties (i.e. the properties of type Form), not the properties of your own form.
Try to encapsulate things. Do not pass a whole form to another form. Instead, pass things that you would like to use on the other form.
A few things are going on here.
You have to use the constructor of Generator that take in a form as a parameter.
You have to expose the datagridview as a public or internal property on the form that you will pass into Generator.
The normal Form class will not know about this property, so you should cast the variable appropriately.
You should call the default constructor of Generator when the other constructor is used to make sure everything is initialized correctly. See code sample below.
Something like this should work:
public class Generator
{
private MyForm myForm;
public Generator()
{
InitializeComponent();
}
public Generator(MyForm frm) : this() // DON'T FORGET THIS()
{
myForm = frm;
}
private void button1_Click(object sender, EventArgs e)
{
myForm.MyDataGridView... // Yay, it works!
}
}
public class MyForm : Form
{
public MyForm()
{
InitializeComponent(); // a datagridview is created here, say "datagridview1"
}
public DataGridView MyDataGridView
{
get { return datagridview1; }
}
}
And then in your button click event (which I assume is defined somewhere in MyForm):
private void button1_Click(object sender, EventArgs e)
{
Form gen = new Generator(this);
gen.Show();
}
The easiest way from there is to open the designer for the DataGridView (myDataGridView) on Form1 and set the Modifiers property from private to internal or public
This will let you call myForm.myDataGridView from the Generator form.

Categories

Resources