Why is the constructor invoked many times? - c#

I am working on silverlight. I created a TextBox and when ever user changed any text in that it should show "*" at the top of file and which should disappear on clicking a save button.
My code works fine for one textbox but when i create second textbox (after the first one) then i found that constructor is invoked two times instead of one. And when i create third textbox(after the two) the constructor is invoked 3 times instead of one. (this textbox is created on a button click in my GUI dynamically which has some text written on it and when i make some change in that text then it shows "*" at top and which disappears on saving it).
Whereas i expect it to be invoked 1 time if i add 1 textbox at a time.
My code to do so is:
private bool modified;
public bool Modified
{
get { return modified; }
set { modified = value; OnPropertyChanged("Modified"); }
}
public ClassConstructor(AnotherClass pv)
{
MessageBox.Show("Number of call check");
setStar(false);
this.isModified = false;
}
private void setStar(bool modified)
{
Tab = this.FileName;
if (modified == false)
{
Tab += "";
}
else
{
Tab += " *";
}
Modified = modified;
}
public void TextChanged(object sender, TextChangedEventArgs e)
{
TextBox tb = (TextBox) sender;
setStar(!TextData.Equals(tb.Text));
}
public void SaveCode(object para)
{
TextData.txt = txt;
setStar(false);
}
Why this constructor is called so many times ? (I mean why my MessageBox for times if i create the fourth textbox) ?

A constructor creates one single instance of that class. So whenever you create a new instance (in your case a new TextBox) the constructor is called to create that object instance. This the sole purpose of constructor - To Be Called when you create an object of that class. Therefore the code inside that constructor is executed. Since you are showing MessageBox inside constructor, you are seeing it 5 times, for 5 new objects and 4 times for 4 new objects. As said in the wiki -
Instance constructors, sometimes referred to as .ctor, are used to
create and initialize any instance member variables when the new
expression is used to create an object of a class.
My first suggestion - Learn what a constructor is because unless you know what a constructor is, you will never understand why this happening. BTW, this is not the error, this is the feature of Object Oriented Programming that whenever you create a new instance, the constructor will be called.
A very good starting point will be here -
Constructor (object-oriented programming)

Related

C# Delegate with Generic T as Button

I'm losing my mind trying to figure this out. I am developing a large windows application that requires all the controls in the main form to have their values updated in near real time. I moved the processing of this continuous method to its own thread, which in general is fine, but I knew that it required me to create a Delegate for setting my controls that were created in a different thread. However, I have a series of buttons that need to have the same various properties set for each one, but with different values. I was thinking I could setup a Delegate with a Generic type being Button, so I could simply pass in the proper button control when it is time to update its properties. But I am missing something, and it doesn't work:
//If this is wrong, please let me know
private delegate void SafeButtonText<T>(string value) where T : Button;
private void SetButtonTextSafe<T>(string value) where T : Button
{
//Using the generic Button passed in, set its values
if (T.InvokeRequired) //This doesn't compile
{
var d = new SafeButtonText<T>(SetButtonTextSafe<T>);
T.Invoke(d, new object[] { value }); //This doesn't compile
}
else
T.Text = value; //This doesn't compile
}
I thought I could use it like this (which doesn't seem possible)
SetButtonTextSafe<qualityButton>(values[0]);
If this is possible, or if there is a much better way of doing this, please feel free to tell me in detail. (if I can using this on a Button, I'd create another delegate for other control types as well)
Thanks in advance.
A type is just that...a type. You can't invoke an instance of it because you have no instance. It is merely reflected metadata.
You need to pass an instance of your button to your method.
private delegate void SafeButtonText<T>(T button, string value) where T : Button;
private void SetButtonTextSafe<T>(T button, string value) where T : Button
{
//Using the generic Button passed in, set its values
if (button.InvokeRequired) //This now compiles
{
var d = new SafeButtonText<T>(SetButtonTextSafe<T>);
button.Invoke(d, new object[] { value }); //This now compiles
}
else
button.Text = value; //This now compiles
}

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);

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.

Method executing several times even though it is called once

I am doing a project which includes dynamic controls creation and removal from the WinForm,
So I decided to that part on a small test project.
Test project has two files Form1.cs and NewControls.cs. This program creates additional buttons whenever user clicks an Add button already on the form.And removes the newly created button when it is clicked (self removal button). Also after removal of button other button's Name, Text and their position are changed according to a local variable (controlIndex).
Form1.cs
public partial class Form1 : Form
{
static List<NewControl> newControlsList = new List<NewControl>();
public Form1()
{
InitializeComponent();
}
private void Add_Click(object sender, EventArgs e)
{
newControlsList.Add(new NewControl(newControlsList.Count));
}
public static void RemoveButton(object sender, EventArgs e)
{
NewControl tempNewControl = (NewControl)(sender as Button).Tag;
tempNewControl.RemoveControl();
newControlsList.Remove(tempNewControl);
MessageBox.Show("Removed!");
foreach (NewControl tempcontrol in newControlsList)
{
tempcontrol.controlIndex = newControlsList.IndexOf(tempcontrol);
tempcontrol.PlaceControl();
}
}
}
NewControl.cs
class NewControl
{
public int controlIndex = 0;
Button newButton = new Button();
public NewControl(int index)
{
controlIndex = index;
PlaceControl();
}
public void RemoveControl()
{
newButton.Dispose();
Form1.ActiveForm.Controls.Remove(newButton);
}
public void PlaceControl()
{
newButton.Tag = this;
newButton.Name = "btn" + controlIndex.ToString("D2");
newButton.Text = "btn" + controlIndex.ToString("D2");
newButton.Size = new Size(100, 20);
newButton.Left = controlIndex * 100;
Form1.ActiveForm.Controls.Add(newButton);
newButton.Click += new EventHandler(Form1.RemoveButton);
}
}
Program works nearly as expected. Problem is the MessageBox which I used in form1.cs in RemoveButton() fires many time (as opposed to just one time), which implies whole method being executed several times. Actually I pasted that MessageBox for debugging (sort of).
Since I cannot debug the application as when "Form1.ActiveForm.Controls.Add(newButton);" statement is executed, debugger Throws NullReferenceException, as there is not an active form while debugging.
I know that's like a bonus question but I thought to just put it there. I am a beginner and can't see the way through both the problems. 1st problem is really important for my original project as it will cause problem when many controls are added.
I think it is because you call PlaceControl from Form1.cs AND in the constructor of the NewControl class, Because you say newButton.Click += new EventHandler(Form1.RemoveButton);.
You are adding EventHandlers, so there can be more of them.
So when you call placeControl multiple times, you've got multiple event handlers, i think.
Probably the EventHandler hasn't been removed by RemoveButton. (I've been working in java most recently so my terms might be a little off for C#.) Suggestion: set control visibility to true when you want it and false otherwise rather than adding and removing.
Everytime a button is removed you go over your existing list of controls, and you call "PlaceControl", which attaches yet another handler.
foreach (NewControl tempcontrol in newControlsList)
{
tempcontrol.controlIndex = newControlsList.IndexOf(tempcontrol);
tempcontrol.PlaceControl();
}
Remove the above code block from RemoveButton, and you will see that your dynamically added buttons will each only trigger the event once.
In your RemoveButton event you loop on each button and call again PlaceControl.
The only reason is to reposition the remainder controls.
I think it's better a call to a separate method that do only this work.
public void RepositionControl()
{
newButton.Left = controlIndex * 100;
}
this will prevent to mess with event handlers added more than one time

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