Modify an object in multiple layers of classes - c#

I have an application with the following:
A data layer class containing the data handling logic and the data itself.
public class DataLayer_JSON
{
CacheData chd = new CacheData();
//The chd object contains the actual data used in the DataLayer_JSON class
public DataLayer_JSON(string relPath) }
A main menu form (essentially it could be just any class)
public partial class MainMenuForm : Form
{
DataLayer_JSON data = new DataLayer_JSON("questions.txt");
...
private void btnEditon_Click(object sender, EventArgs e)
{
...
using (var EF = new EditorForm(data.GetCathegories(), data.GetDifficulties(), data.GetQuestions()))
{
var result = EF.ShowDialog();
if(result == DialogResult.OK)
{
data.ClearQuestions(); //Clear all cached questions
//Since we are still in scope of the EditorForm (EF) within the using clause, we can access it's members
data.AddQuestionRange(EF.AllQuestions); //Replace cache with the edited list
}
}
...
//Here we save the data permanently to a text file when closing the program.
//This could also be done from the EditorForm if we wanted to
private void MainMenuForm_FormClosing(object sender, FormClosingEventArgs e)
{
data.Save("questions.txt");
}
An editor form (started from #2)
public EditorForm(IEnumerable<INameObject> Cathegories, IEnumerable<INameObject> Difficulties, IEnumerable<Question> oldQuestions)
{
...
}
In #2, I create and initialize the data layer instance (#1). I want to modify the data contained in #1 from within #3, but so far, I have only been able to pass by value the contents from #1 to #3, via #2. The results are then returned from #3 to #2 and handled there.
I've read about passing by reference in C#, but my conclusion is that you cant assign a variable to the reference, and then have that variable modify the original data.
I read about the references in C# in the following places this time, as well as reading extensively about this topic many times before:
C# reference assignment operator? How do I assign by "reference" to a class field in c#?
So the question is:
How can I go about changing the content of an instance of #1 directly in #3?

How can I go about changing the content of an instance of #1 directly in #3?
Well, you'd start by passing the instance of #1 to #3. Currently you are not doing that.
So for example:
public EditorForm(DataLayer_Json data)
{
...
}
and
using (var EF = new EditorForm(data))
Then inside the EditorForm, you can do whatever you want to data (except for reassigning the actual reference) and those changes will be reflected outside of EditorForm as well.
data.ClearQuestions(); // Works fine, mutating the object.
data = new DataLayer_JSON(); // Doesn't affect the `data` variable that was passed in.

Related

Error message "An object reference is required for the non-static field, method or property."

I am creating a program to access a database.
The code that is causing me trouble is meant to open a new form when a button is pressed. It then gets data based on the selected values in a listbox on the main form and is needed to send that data to the second form to be placed in textboxes and labels.
The problem I have, is that in order for the code to execute without throwing the Error
"An object reference is required for the non-static field, method or property..."
I must make the method in the secondary form static; however this prevents me from accessing the controls on the secondary form.
Main Form Code Snippet:
private void MemView_Click(object sender, EventArgs e)
{
string selected = lstMember.SelectedItems[0].Text;
//MessageBox.Show(selected);
string[] data = P.selectMem(selected);
MessageBox.Show(data[0]);
MemForm mem = new MemForm(); //How to open a designed form
mem.Show(); //Displays the addmem form
MemForm.getData(data);
}
Secondary Form Code Snippet:
public void getData(string[] Data)
{
int index = 0;
bool loop = false;
string text;
while (loop == true)
{
if (index < 10)
{ text = "tb0" + index.ToString(); }
else
{ text = "tb" + index.ToString(); }
index = index + 1;
}
}
My secondary code snippet is meant to use the loop to fill all the data into the textboxes without me having to manually write out each tb00.Text = data[] etc.
I am unable to access the FindControls() method in C# most likely due to the need for a static method.
The P class used in the Main Form performs the SQL code and is working fully.
I've tried to give enough information for an answer, however if more is needed just ask in a comment I will try and provide more. :)
If getData() is a non-static method in MemForm, you need an instance of MemForm to use it. You have one: MemForm mem = new MemForm(); Use the mem object which is an instance of MemForm.
mem.getData(data);

pass DataStruct around more efficiently (winforms)

i have a DataStruct[] that gets used multiple times on a form. It is created from reading a CSV file. The structure has 5 "columns", each with about 100,000 rows
in particular, i have a bunch of ChangeEvents (trackbars, textboxes, etc.), where each change event is re-making the data structure, but i feel it's slowing down the changes (they are rendering on a graph, and it's slow to react)
once i have the actual structure, i don't need to change it, i just need to work with the data. I don't know how i can create the DataStruct[] only once, then pass that struct into the various change events without rebuilding it
the following code currently exists in all my change events (edited for brevity):
string[] fileArray = File.ReadAllLines(tempfile);
DataStruct[] data = new DataStruct[fileArray.Length];
for (int i = 0; i < fileArray.Length; i++)
{
List<string> dataList = fileArray[i].Split(',').ToList<string>();
data[i].X = (Convert.ToSingle(dataList[0]));
}
my confusion is: i have a variety of void() methods that use the structure, and it's easy to pass into those. however i don't understand how to pass into a change event, since the handler refreshes every time the change occurs, i don't know where to call the pass. For example:
private void trackBar1_Scroll(object sender, EventArgs e)
{
label282.Text = trackBar1.Value.ToString();
chart17.Series[0].Points.Clear();
VoltageChanger();
}
how would i call this Scroll change without re-doing the struct? VoltageChanger() uses the struct to do some stuff and make a new graph based on the trackbar value.
or...am i silly in thinking that there may be a slowdown here, and it's just the graph rendering that won't get any better?
thanks (edit: i have been reading but event handling outside of the winforms defaults is currently new to me)
I suggest you read up on variable scope here. For your example, you need to read the information once and have it accessible to all the methods within the class. That is what a module-level variable will do. In the code snippet below, notice the declaration for DataStruct is within the class definition, not within any individual method. This makes the variable visible to that class' methods.
public partial class Form1 : Form
{
private DataStruct[] _data; // <-- Module level variable
public Form1()
{
InitializeComponent();
LoadData();
}
private void LoadData()
{
// Open file code omitted
_data = new DataStruct[fileArray.Length];
// Read data into file omitted
}
private void Method1()
{
// _data will be accessible here because it is a module-level variable
}
}

use PictureBox from another class c#

I hope my question will be clear
In Form1.cs i have PictureBox named: ico_ok
i would like to use this PictureBox in my new class that i bulit.
when i start typing ico... nothing appears.
what is the way to use this object in another class?
here the code:
public void button2_Click(object sender, EventArgs e)
{
lbl_check.Visible = true;
btn_continue.Visible = false;
txtbox_cusnumber.Enabled = false;
string userID = (txtbox_cusnumber.Text.ToString());
CheckOUinADexist checkou = new CheckOUinADexist(userID);
}
after that look at the new class:
namespace ChekingOUinActiveDirectory
{
class CheckOUinADexist
{
public CheckOUinADexist(string userID)
{
//this place i would like to use ico_ok
}
}
}
Thank you for helping.
Maayan
The simplest approach is probably to provide that class with the dependency on the PictureBox:
public CheckOUinADexist(string userID, PictureBox pbox)
{
pbox.[your code]
}
Then supply it when calling the method:
CheckOUinADexist checkou = new CheckOUinADexist(userID, ico_ok);
Whether or not this is the ideal approach depends on what you're going to be doing with that PictureBox inside that object, how portable that object needs to be across technology platforms, etc.
In general you don't want UI elements to permeate into non-UI logic. If CheckOUinADexist is a UI-bound class and exists solely to help the UI, then this isn't a problem. If it's part of business logic then you wouldn't want to couple that logic with the UI technology. Instead, you'd likely pass it the data needed from the PictureBox, but not the PictureBox itself.
This all depends a lot on the overall architecture of what you're trying to achieve here, which we don't know.
Basically you'd give the target class a reference to the "shared data" -- picture box in this case.
class CheckOUinADexist
{
PictureBox _picBox
public CheckOUinADexist(string userID, PictureBox picBox)
{
//this place i would like to use ico_ok
_picBox = picBox;
_picBox.myAction();
}
}
Whether you want to actually stored Picturebox as a field (as opposed to just use a parameter) depends on whether you need access to the field throughout the lifetime of the instance(s) or whether it is just needed for object construction. If you are not sure, you are safer (IMHO) just storing a reference in a field. Make further uses of it a lot easier.

Why Windows Form TextBox won't update from outside class?

Newbie here. I'm running Visual Studio C# Express 2008. I have two Windows Forms, each with a TextBox. The textboxes update within the same class but not as the result of a invoked method from outside the class. I need to be able to update tbRooms.Text when the UpdateListOfRooms() method is invoked. I've outlined the problem in pseudo-code below. I appreciate your help!
fLocations.cs
fLocations_Load()
{
this.tbLocations.Text = Properties.Settings.Default.LocationID + " locationsLoad"; --updates
}
dgvLocations_SelectionChanged()
{
var rooms = new fRooms();
rooms.tbRooms.Text = Properties.Settings.Default.LocationID + " locationssSelectionChanged"; --updates
rooms.UpdateListOfRooms();
}
fRooms.cs
fRooms_Load()
{
this.tbRooms.Text = Properties.Settings.Default.LocationID + " roomsLoad"; --updates
}
UpdateListOfRooms()
{
this.tbRooms.Text = Properties.Settings.Default.LocationID + " roomsUpdateListOfRooms"; --does NOT update; still says "roomsLoad"
}
Updated 8/20/14:
I've been a busy bee :) I read all the parts of the tutorial by #jmcilhinney and decided to approach this by including references to the two forms, Locations and Rooms, in the MainMenu class that launches them:
(MainMenu.cs) Instances of Locations and Rooms are created. In the constructor, 'rooms' is passed to the 'locations' instance and both forms are shown.
(Locations.cs) Another Rooms instance is created at class scope so it can be seen by all methods of the class. In the constructor, this instance is set to the one being passed by MainMenu which means that this class is working with the same instance created in MainMenu. When the user changes the selection on dgvLocations, the 'dgvLocations_SelectionChanged' event is fired which invokes the Rooms.UpdateRooms method.
(Rooms.cs) The 'UpdateRooms' method displays a new set of rooms based on the passed value of 'locationID'.
This link was helpful. Visual C# - Access instance of object created in one class in another.
public partial class MainMenu : Form
{
Locations locations;
Rooms rooms;
public MainMenu()
{
rooms = new Rooms();
locations = new Locations(rooms);
locations.Show();
rooms.Show();
InitializeComponent();
}
}
public partial class Locations : Form
{
Rooms rooms;
public Locations(Rooms r)
{
rooms = r;
InitializeComponent();
}
private void Locations_Load(object sender, EventArgs e)
{
// Populate this.dgvLocations using SQL query.
}
private void dgvLocations_SelectionChanged(object sender, EventArgs e)
{
// Update the rooms instance with current locationID.
rooms.UpdateRooms(dgvLocations.CurrentCell.Value.ToString());
}
}
public partial class Rooms : Form
{
public Rooms()
{
InitializeComponent();
}
private void Rooms_Load(object sender, EventArgs e)
{
// Populate this.dgvRooms using SQL query.
}
public void UpdateRooms(string locationID)
{
// Update dgvRooms based on user changing the locationID in dgvLocations
}
}
In the first code snippet, you create a new fRooms object but you never call its Show or ShowDialog method, which means that you never display it to the user. That means that any changes you make to that form will not be seen. Presumably the user can see an fRooms object though, but you are not making any changes to that one.
Consider this. Let's say that I give you a note pad and you open it and look at the first page. Let's say that I now buy a new note pad and write on the first page of it. Would you expect to see the words I wrote magically appear on the page in front of you? Of course not. We both are holding a note pad but they are two different note pads. You're looking at one and I'm writing on the other, so you won;t see what I write.
The same goes for your forms. They are both fRooms objects but they are two different fRooms objects. Changes you make to one will not affect the other. If you want the user to see the changes you make then you must make those changes to the fRooms object that the user is looking at.

Access variable inside the tab page of the Form

Here I'm facing problem,I'm adding form dynamically into tab page.
I have to get a static variable from that form.
i used code,but i can't get exact value which i need.
private void timer2_Tick(object sender, EventArgs e)
{
foreach (TabPage page in tabControl1.TabPages)
{
Control control = page.Controls[0];
if(!hyber.Form1.receiverflag)//bug line
{
tabControl1.TabPages.Remove(page);
}
}
}
In the above pic watch window
page.controls[0]
->[hyber.form1]
-->receiverflag
how to get that variable value.
Thanks in advance.
you are nor clear about bug line or in saying can't get the exact value you need.
if the variable is a public static bool it belongs to the class and not to the instance, being static, so when you write:
hyber.Form1.receiverflag
you are taking the variable's value regardless of the specific instance of Form1 you are dealing with, does not matter at all if you have created one instance and added to the TabPage, that variable always exists even if you do not create any instance.
if you are getting wrong/unexpected results could be, eventually, that another thread or another method has changed the value of that static field and this reflects everywhere in your application.
Edit: if it was not static, you could probably get what you are asking in this way:
var yourForm1 = (page.Controls[0] as hyber.Form1);
if( yourForm1 != null && !yourForm1.receiverflag)
{
....

Categories