I currently have a class that handles my treeview and other winForm components.
I want to use another form which act as my input and once I press the save button it should update my treeview component on the other form. So far what I tried has not worked.
here is my code:
*mainDisplay is my form which includes my component and stores my variable that holds the data
Here I load my date into the treeview
public void mainDisplay_Load( TreeNode input)
{
treeView1.BeginUpdate();
foreach (data x in mydata1)
{
Console.WriteLine(x.getName());
if (x.getName() != null)
{
treeView1.Nodes.Add(input);
}
}
treeView1.Refresh();
}
here is my button action on the OTHER form:
private void button1_Click(object sender, EventArgs e)
{
if (!(String.IsNullOrEmpty(getnamebox.Text))) ;
{
mainDisplay putdata = new mainDisplay();
name = getnamebox.Text;
pass = getpassbox.Text;
url = geturlbox.Text;
notes = getnotebox.Text;
data newData = new data(name, pass, notes);
mainDisplay.mydata1.Add(newData);
TreeNode mytree = new TreeNode(name);
putdata.mainDisplay_Load(mytree);
this.Hide();
}
Any tip would be appreciated.
You just created a brand new main display form somewhere (in memory) and added a tree node to it.
You need to pass the reference of your main display forward (usually in an initialize function or trace back your second form's parentage depending on how your stuff was set up) and then use the reference to your actual main form to update the tree.
Related
My question is about dealing with multiple forms in C# Windows form application. I am developing a code for playing a movie and moving it frame by frame with buttons. I already have the code for moving the movie frame by frame with ctlcontrols in Windows Media Player.
The thing that I'm having an issue with is that I want to have a main form and a movie form, and when I click the button in the main form, I want to send a number to the other form and if the number was 2, I want the movie to go frame by frame in the movie form. And I want to do it without opening a new form every time I click the button. I have made a function in my second form and I called it in the button in the main form. It is expected to work but it doesn't.
The code for the button in the main form is:
private void button1_Click(object sender, EventArgs e)
{
value = txtSendNum.Text; // get the value from the textox and
// assign it to string variable
MovieForm movieform = new MovieForm(); //create an object for MovieForm
movieform.ConnectForms(value);
}
The code for the function(ConnectForms function) in the second form is:
public void ConnectForms(string value)
{
val = Convert.ToInt32(value);
if (val == 2)
{
axWindowsMediaPlayer1.Ctlcontrols.play();
axWindowsMediaPlayer1.Ctlcontrols.currentPosition += 0.5;
axWindowsMediaPlayer1.Ctlcontrols.stop();
}
}
You are creating a new MovieForm every time the user clicks the button, this is wrong. You need a reference to the MovieForm that was previously open.
This is the difference between the meaning of Object and Class. You need a reference to the object not a new object from the same class.
A simple way to make it work is like the following code:
MovieForm movieform = null;
private void button1_Click(object sender, EventArgs e)
{
value = txtSendNum.Text;
if(movieform == null || movieform.IsDisposed)
{
movieform = new MovieForm(); //create an object for MovieForm
movieform.Show();
movieform.ConnectForms(value);
}
else
{
movieform.ConnectForms(value);
movieform.Focus();
}
}
You must have a reference the the other form. Instead of declaring movieform as a local variable, declare it as a class level variable (i.e., a field)
private MovieForm _movieform = new MovieForm();
private void button1_Click(object sender, EventArgs e)
{
value = txtSendNum.Text; //get the value from the textox and assign it to string variable
_movieform.ConnectForms(value);
_movieform.Show();
}
A local variable, i.e., a variable declared in a method has a lifetime limited to one method call (I'm not talking about special cases like iterators and closures).
A class field has the same lifetime as the object (here the Form).
Instead of creating a method on each form that receives a value or passing the value as parameter on the constructor of each form, or creating a new property to set the value to search for it later you should use the Tag property of the Control that is already created for that. Here you is how it is used
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.tag?view=netframework-4.7.2
private void buttonNewCustomer_Click(object sender, EventArgs e)
{
/* Create a new customer form and assign a new
* Customer object to the Tag property. */
CustomerForm customerForm = new CustomerForm();
customerForm.Tag = new Customer();
customerForm.Show();
}
I have a dictionary list of forms which are Documents within DockPanelSuite (Windows Forms) When a button on the main form is pressed all the document's "Contents" contained in the first control (ScintillaNet Editor instance) of the Document Form should be saved.
However, accessing the Save() method of the form is proving frustrating.
Currently this is the code:
private void btnCompile_Click(object sender, EventArgs e)
{
// Save the Project.
foreach(var editor in EditorList)
{
if(editor.Key.StartsWith(CurrentProjectModel.Name))
{
FrmCodeEditor fce = new FrmCodeEditor();
fce = (FrmCodeEditor)editor.Value;
fce.Save();
}
}
IDA.Controllers.CLI.Exec exec = new Controllers.CLI.Exec();
exec.ExecuteCompiler();
}
editor is the name of the form, EditorList is the Dictionary which contains a list of all active Documents. However, the fce.Save is not being found.
Question
All I want to do is iterate through all the open Documents which are FrmEditor types and call their Save method. How can I do that?
As it turned out - the method I was trying to call was static. However, this was not being flagged in intellisense.
I have a problem with not being able to refresh my form that has a DataGridView.
I open a form called MaintenanceForm.
Here I will choose a car, give the amount of km, and the option to add products.
If I click on the add products button, this form will stay open while another will open as well called AddProducts. In this form I will choose from a list of products that I will add to my final listbox. If I click Save, these items will go to my BindingList and populate my grid.
I have tested this with closing my first form first and reopening it with my second form. The grid was populated.
How do I populate my grid without having to close my first form?
Here are the methods I'm using
Save button on my second form:
private void btnOpslaan_Click(object sender, EventArgs e)
{
lstTotal = new BindingList<Product>();
foreach (object product in listBtotal.Items)
{
lstTotal.Add((Product)product);
}
MaintenanceForm maintenanceForm = new MaintenanceForm();
maintenanceForm.FillDataGridView(lstTotal);
this.Close();
}
Method to populate my grid:
public void FillDataGridView(BindingList<Product> products)
{
dGvProducts.DataSource = null;
dGvProducts.AutoGenerateColumns = false;
dGvProducts.AllowUserToAddRows = false;
dGvProducts.DataSource = products;
dGvProducts.Refresh();
}
Again the MaintenanceForm is still open while AddProductsForm is open?
Thanks in advance
Thanks to the user JDB i have fixed my problem.
Instead of making a new instance (Thank you Junaith for correcting me for it) I'm now making a LogicalParent method.
public AdminForm LogicalParent { get; set; }
With this i have access to al methods and functions of my parent Form and no problems with refreshing.
I have got three forms and on one of them there is a combobox which is supposed to change icons on all my running forms and images of buttons located on another forms, when selected value of the combobox is changed.
Please note that the problem is solved when it comes to changing icons, but I need solution for changing buttons images. I have managed to do so on just one form (where the combobox is located). I cannot figure out how to customise buttons on other forms as well.
I have tried this way:
private void combo_Theme_SelectedValueChanged(object sender, EventArgs e)
{
Main f1 = new Main();
if (combo_Theme.Text == "Purple")
{
foreach (var form in Application.OpenForms.Cast<Form>())
{
form.Icon = Properties.Resources.Purple;
f1.btn_Exit.Image = Properties.Resources.EXIT_purple;
}
}
... but had no success.
Basically, I am stuck now, since the code above doesn't work for me.
Any ideas?
You should re-design your forms by implementing some interface with some method, calling that method will actually update the images of the buttons on a specific form. That way you don't have to loop through each controls (in nested relationship) and check out every button. However if your forms don't have complex nested relationship and the number of buttons is small, we can use the following code, in fact this code still works OK (responsive enough) when you have thousands of controls on a form with several nested containers):
public IEnumerable<Button> GetAllButtons(Form form){
Stack<Control> controls = new Stack<Control>();
controls.Push(form);
while(controls.Count > 0){
var control = controls.Pop();
foreach(var c in control.Controls){
if(c is Button) yield return c;
controls.Push(c);
}
}
}
//now use that method in your code like this:
private void combo_Theme_SelectedValueChanged(object sender, EventArgs e)
{
Main f1 = new Main();
if (combo_Theme.Text == "Purple")
{
foreach (var form in Application.OpenForms.Cast<Form>())
{
form.Icon = Properties.Resources.Purple;
f1.btn_Exit.Image = Properties.Resources.EXIT_purple;
//looping through each button on the current form
foreach(var button in GetAllButtons(form)){
//your code here
button.Image = Properties.Resources.EXIT_purple;
}
}
}
//...
}
I currently have a parent control (Form1) and a child control (Form2).
Form1 contains a listview that stores a list of of file data (each file is a separate item).
Form2 contains only a textbox.
Upon clicking on one of these listviewitems in Form1, Form2 is opened up and accesses the file's data and loads it into the textbox in Form2 in plain text format.
The issue I'm having is, I would like to be able to detect, upon clicking of a listviewitem, whether that file is already opened in said child form and if so, to activate it (bring it to the front) and if it is not already opened, open it. I'm not sure what the best method of doing this would be since this can involve many child forms being open at once. This is not an MDI application. Any ideas on how this could be accomplished are appreciated and samples even more so. Thank you.
What I have done in the past is give each new form a unique tag (based on the file you're viewing in this case), so:
var form = new Form2();
form.Tag = (object)"My Unique Object as a Tag"; // Redundant cast I know, but shows Tag is of type object
Then, when going to open up a window for a file, iterate over all the open forms checking tags like so:
foreach(var f in Application.OpenForms)
{
if(f.Tag == tagForFile)
{
f.BringToFront();
return;
}
}
// Couldn't find one, so open on
var form = new Form2();
form.Tag = tagForFile;
form.Show();
And this should only open up one form per file (or tag really)
Hopefully that helps !
You could simply maintain a Dictionary<ListViewItem,Form>. Each time you open a new form add an entry to the dictionary. If the dictionary already contains the ListViewItem that was clicked as a key then you don't need to open a new form.
Assuming form is created for every selected item you could keep track of opened forms in ListViewItem's tag.
lv.ItemSelectionChanged += lv_ItemSelectionChanged;
private void lv_ItemSelectionChanged(Object sender, ListViewItemSelectionChangedEventArgs e)
{
if(e.IsSelected)
{
if(e.Item.Tag == null)
{
var form = new Form2();
// init Form2 here
form.Parent = this.panel1;
e.Item.Tag = form;
}
(e.Item as Form2).BringToFront();
}
}
EDIT:
On the other hand why would you create and switch between forms which have only one Edit, it would be much simpler to just fill TextBox with file contents:
ListView1.ItemActivate += ListView1_ItemActivate;
private void ListView1_ItemActivate(Object sender, EventArgs e)
{
if(ListView1.SelectedItems.Count > 0)
{
this.form2Instance.ContentsTextBox.Text = File.ReadAllText(this.rootFilesPath + #"\" + ListView1.SelectedItems.Last().Text));
}
}
And if you wamt to read file contents only once, just save file contents in ListViewItem's tag
ListView1.ItemActivate += ListView1_ItemActivate;
private void ListView1_ItemActivate(Object sender, EventArgs e)
{
if(ListView1.SelectedItems.Count > 0)
{
var item = ListView1.SelectedItems.Last();
if(item.Tag == null)
item.Tag = File.ReadAllText(this.rootFilesPath + #"\" + item.Text);
this.form2Instance.ContentsTextBox.Text = (string) item.Tag;
}
}