I am a novice to C# language. I have created a user form and added a listview (chnaged it to public) on it. Now I have added a static classlike this
public static class listView
{
private static ListView.ListViewItemCollection litm;
public static ListView.ListViewItemCollection listItems
{
get
{
Form1 frm = new Form1();
return frm.listView1.Items;
}
set
{
litm = value;
}
}
}
Now added following code behind a button ,
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(listView.listItems.Count.ToString()); //Works
listView.listItems.Add("Fail"); //Fails
this.listView1.Items.Add("HH"); //Works
}
Here, I am able to use get the count of items. I think get works. But when I am trying to add a new item, it does nothing. No error but no entry is added.
I am interested to learn why that's happening. Any guidance is appreciated.
In your getter for property, you are creating a new instance of form 1 and add item to that.
It is not related to being static or non-static.
Look at this:
get
{
Form1 frm = new Form1();
return frm.listView1.Items;
}
So when you
listView.listItems.Add("Fail");
you are adding item to list view of form 1 that you can't see it.
Infact every time you access listView.listItems property, you are creating a newinstance of form 1 and adding an item to its listview1.
But in this line:
this.listView1.Items.Add("HH");
you are adding the item to the list view that you are seeing.
To learn about static:
static (C# Reference)
Related
From what i've read so far i've done this:
On my first form:
public partial class FPrincipal : Form
{
List<Grua> ListaGruas = new List<Grua>();
List<Semirremolques> ListaSemirremolques = new List<Semirremolques>();
List<Clientes> ListaClientes = new List<Clientes>();
// this is the menu strip i click to create my new form,
// send my list and add my values
private void miEquipoCargar_Click(object sender, EventArgs e)
{
EquiposCargar FormEquiposCargar = new EquiposCargar(ListaGruas);
FormEquiposCargar.ShowDialog();
}
}
And on my second form:
public partial class EquiposCargar : Form
{
// I saw some videos on youtube and this is how the pass some values,
// but it doesnt work with lists
public EquiposCargar(List<Grua>listaGrua)
{
InitializeComponent();
}
}
Could anyone please help me? im stuck.
The error says the parameter List<Grua>listaGrua is less accesible than the method EquiposCargar.EquiposCargar(List<Grua>)
just another question! how do i use the list on my second form? lol...
because it says the name listaGrua is not defined in the actual
content. It looks like i have to create a new variable and assign the
list parameter than i sent, right? but im doing it and its still not
working
That's correct, you need to create a variable in your second form to hold that reference. In the constructor, simply assign the passed in reference to your form's reference:
public partial class EquiposCargar : Form
{
private List<Grua> listaGrua;
public EquiposCargar(List<Grua> listaGrua)
{
InitializeComponent();
this.listaGrua = listaGrua;
}
}
Note the use of the this keyword. Now you should be able to use listaGrua from anywhere in your second form.
I know this might look silly but I got a strange problem in my winforms. I have a windows application in which after a particular set of operations are completed I want to populate a Checked ComboBox. I am doing this using two classes. I want to copy a array from helper class to the form class. Array gets copied when AddArrayItems method is called. But when I see the ComboBox in the form, its null. After debugging with watch variables I got to know that the problem is after copying the array to Form1 array, as soon the control goes back to the caller, the array items are deleted. I tried to replicate my stuff, not exactly but still similar to what I am doing.
My code looks like this:
using System;
using System.Windows.Forms;
namespace DemoApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string[] cboxAr;
public void AddCmboBoxItems(string[] cbArry)
{
cboxAr = new string[cbArry.Length];
Array.Copy(cbArry, 0, cboxAr, 0, cbArry.Length);
//cbArry.CopyTo(cboxAr, 0);
//foreach (string s in cboxAr)
//comboBox1.Items.Add(s);
comboBox1.Show();
}
private void button1_Click(object sender, EventArgs e)
{
HelperClass.DoSomething();
}
}
public class HelperClass
{
public HelperClass()
{
}
public void HelperMethod()
{
SomeMethod();
}
private void SomeMethod()
{
string[] partnrName = new string[5] { "str1", "str2", "str3", "str4", "str5"};
Form1 f = new Form1();
f.AddCmboBoxItems(partnrName);
}
public static void DoSomething()
{
new HelperClass().HelperMethod();
}
}
}
I don't understand what exactly the problem is here. Can anyone please push me in the right direction. Thanks in advance.
You're never showing the form after modifying its controls:
Form1 f = new Form1();
f.AddCmboBoxItems(partnrName);
But you're calling this from within an existing form:
private void button1_Click(object sender, EventArgs e)
{
HelperClass.DoSomething();
}
Presumably you want to modify the controls on that form? Then you'll need a reference to that form. Pass one to the method:
private void button1_Click(object sender, EventArgs e)
{
HelperClass.DoSomething(this);
}
And accept it in the method definition:
public static void DoSomething(Form1 form)
{
new HelperClass().HelperMethod(form);
}
And so until the point where you need to use it. (Side note: You have a lot of weird indirection happening here with a seemingly random mix of static and instance methods and classes. You can simplify a lot, which will make this involve fewer code changes.)
Ultimately, SomeMethod needs the instance of the form to modify:
private void SomeMethod(Form1 form)
{
string[] partnrName = new string[5] { "str1", "str2", "str3", "str4", "str5"};
form.AddCmboBoxItems(partnrName);
}
To illustrate the overall point, consider an analogy...
A car rolls off of an assembly line. You open the trunk and put a suitcase inside. Moments later another car rolls off of the same assembly line. It is identical to the first car in every way. When you open the trunk of the second car, do you expect to find your suitcase inside it?
A Form is an object like any other. Changes made to one instance of an object are not reflected in other instances of the same object. Each instance maintains its own state. In order to modify a particular instance, you need a reference to that instance.
I have been trying to create a small form application and I wanted to try out binding a DataGridView directly to a collection of objects.
I created the following classes
public class MyClassRepository
{
public List<MyClass> MyClassList { get; set; } = new List<MyClass> { new MyClass { Name = "Test" } };
}
public class MyClass
{
public string Name { get; set; }
}
and I added the following code to a form to test. I based this off of the code in the designer after setting the BindingSource through the UI (while following this walk through https://msdn.microsoft.com/en-us/library/ms171892.aspx)
var tmp = new BindingSource();
tmp.DataMember = "MyClassList";
tmp.DataSource = typeof(MyClassRepository);
When this didn't work I started running through the code behind BindingSource to see what was happening. The setter calls ResetList which tries to create a dataSourceInstance by calling ListBindingHelper.GetListFromType. This call ultimately calls SecurityUtils.SecureCreateInstance(Type) where type is a BindingList<MyClassRepository>. This passes null to args which is passed Activator.CreateInstance which returns an empty collection.
After this ListBindingHelper.GetList(dataSourceInstance, this.dataMember) is called. This method calls ListBindingHelper.GetListItemProperties which results in a PropertyDescriptor for my MyClassList property and assigns it to dmProp.
At this point GetList calls GetFirstItemByEnumerable(dataSource as IEnumerable) where dataSource is the previously created (and empty) instance of BindingList<MyClassRepository> and returns (currentItem == null) ? null : dmProp.GetValue(currentItem);.
The value of dmProp/MyClassList is never accessed and the BindingSource is never populated with the instance I created. Am I doing something wrong? If not is there a bug in the source code? It seems to me like either SecureCreateInstance(Type type, object[] args) should be called and MyClassList should be passed via args instead of the existing call to SecureCreateInstance(Type type) or the value of dmProp should be used regardless?
If that is not correct how do I make the Designers automatically generated code set the DataSource to an instance of the object? Or do I have to inherit from BindingSource? If the latter why does it give you the option to choose a class that does not inherit from BindingSource?
As Reza Aghaei points out, in the designer, setting the BindingSource.DataSource to the “MyClassRepository” may work, however you still need to initialize (create a new) MyClassRepository object. I do not see this line of code anywhere in the posted code: MyClassRepository myRepositiory = new MyClassRepository(); The data source is empty because you have not created an instance of “MyClassRepository” and as Reza points out, this is usually done in the forms Load event.
To keep it simple, remove the DataSource for the BindingSource in the designer and simply set up the BindingSource’s data source in the form load event like below. First, create a new “instance” of the MyClassRepository then use its MyClassList property as a data source to the BindingSource. I hope this helps.
MyClassRepository repOfMyClass;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
repOfMyClass = new MyClassRepository();
bindingSource1.DataSource = repOfMyClass.MyClassList;
dataGridView1.DataSource = bindingSource1;
}
Edit-----
After further review… I agree that you should be able to do as you describe. I was able to get it working as expected with the code below.
BindingSource bindingSource1;
private void Form1_Load(object sender, EventArgs e) {
bindingSource1 = new BindingSource();
bindingSource1.DataSource = typeof(MyClassRepository);
bindingSource1.DataMember = "MyClassList";
dataGridView1.DataSource = bindingSource1;
}
I followed the same steps in the “designer” and it worked as expected. Is there something else I am missing? As you stated… using MyClassRepository mcr = new MyClassRepository() appears to be unnecessary. In addition, if you cannot get it to work using one of the two ways above… then something else is going on. If it does not work as above, what happens?
Edit 2
Without creating a “new” MyClassRepository, object was unexpected and I did not realize that new items added to the list/grid were going into the bindingSource1. The main point, is that without instantiating a “new” MyClassRepository object, the constructor will never run. This means that the property List<MyClass> MyClassList will never get instantiated. Nor will the default values get set.
Therefore, the MyClassList variable will be inaccessible in this context. Example in this particular case, if rows are added to the grid, then bindingSource1.Count property would return the correct number of rows. Not only will the row count be zero (0) in MyClassList but also more importantly… is “how” would you even access the MyClassList property without first instantiating a “new” MyClassRepository object? Because of this inaccessibility, MyClassList will never be used.
Edit 3 ---
What you are trying to achieve can be done in a myriad number of ways. Using your code and my posted code will not work if you want MyClassList to contain the real time changes made in the grid by the user. Example, in your code and mine… if the user adds a row to the grid, it will add that item to the “bindingSource” but it will NOT add it to MyClassList. I can only guess this is not what you want. Otherwise, what is the purpose of MyClassList. The code below “will” use MyClassList as expected. If you drop the “designer” perspective… you can do the same thing in three (3) lines of code... IF you fix the broken MyClassRepository class and create a new one on the form load event. IMHO this is much easier than fiddling with the designer.
Changes to MyClassRepository… added a constructor, added a size property and a method as an example.
class MyClassRepository {
public List<MyClass> MyClassList { get; set; }
public int MaxSize { get; set; }
public MyClassRepository() {
MyClassList = new List<MyClass>();
MaxSize = 1000;
}
public void MyClassListSize() {
MessageBox.Show("MyClassList.Count: " + MyClassList.Count);
}
// other list manager methods....
}
Changes to MyClass… added a property as an example.
class MyClass {
public string Name { get; set; }
public string Age { get; set; }
}
Finaly, the form load event to create a new MyClassRepository, set up the binding source to point to MyClassList and lastly set the binding source as a data source to the grid. NOTE: making myClassRepository and gridBindingSource global variables is unnecessary and is set this way to check that MyClassList is updated in real time with what the user does in the grid. This is done in the button click event below.
MyClassRepository myClassRepository;
BindingSource gridBindingSource;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
try {
myClassRepository = new MyClassRepository();
gridBindingSource = new BindingSource(myClassRepository.MyClassList, "");
dataGridView1.DataSource = gridBindingSource;
}
catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
}
private void button1_Click_1(object sender, EventArgs e) {
MessageBox.Show("Binding source count:" + gridBindingSource.Count + Environment.NewLine +
"MyClassList count: " + myClassRepository.MyClassList.Count);
}
I hope this makes sense. ;-)
Designer sets DataSource = typeof(Something) for design-time support, for example to let you choose DataMember from a dropdown or to let you choose the data source property from dropdown while setting up data-bindings.
How do I make the Designers automatically generated code set the
DataSource to an instance of the object?
Forcing the designer to do that doesn't make much sense, because the designer doesn't have any idea about what the real data source you are going to use to load data. It can be a web service, a WCF service, a business logic layer class.
So at run-time you need to assign an instance of your list to DataSource. For example in Load event of the form.
I want to access the list box and add the item into it for my Custom control which is dynamically created on run time. I want to add the Item when I press the button place in the custom control, but it does not work. I have use the following code to work:
private void button1_Click(object sender, EventArgs e)
{
Form1 frm = new Form1();
frm.ABC = "HI";
}
the 'ABC' is the Public string on the form ie:
public string ABC
{
set { listBox1.Items.Add (value); }
}
the above string works fine when I use it form the Button on the form and it adds the value in the lsitbox but whent I use it form the custom control's button the text of the 'value' changes but it does not add the item in list box.I have also try it on tabel but does not help. I change the Modifires of the ListBox1 from Private to Public but it does not works. The above function works well in the form but cannot work from the custom control.
Thanks.
Expose an event ("ItemAdded" or whatever) in the child form that your main form can handle. Pass the data to any event subscribers through an EventArgs derived object. Now your mainform can update the UI as it please with no tight coupling between the two classes. One class should not know about the UI layout of another, it's a bad habit to get into (one that everyone seems to suggest when this question crops up).
What I think you should use is
this.ParentForm
So in your case it should be:
public string ABC
{
set { this.ParentForm.listBox1.Items.Add (value); }
}
The easiest way would be to pass the form down into your custom control as a parameter in the constructor that way you could access it from the custom control.
EX:
public class CustomControl
{
private Form1 _form;
public CustomControl(Form1 form)
{
_form = form;
}
private void button1_Click(object sender, EventArgs e)
{
_form.ABC = "HI";
}
}
In Visual C# when I click a button, I want to load another form. But before that form loads, I want to fill the textboxes with some text. I tried to put some commands to do this before showing the form, but I get an error saying the textbox is inaccessible due to its protection level.
How can I set the textbox in a form before I show it?
private void button2_Click(object sender, EventArgs e)
{
fixgame changeCards = new fixgame();
changeCards.p1c1val.text = "3";
changeCards.Show();
}
When you create the new form in the button click event handler, you instantiate a new form object and then call its show method.
Once you have the form object you can also call any other methods or properties that are present on that class, including a property that sets the value of the textbox.
So, the code below adds a property to the Form2 class that sets your textbox (where textbox1 is the name of your textbox). I prefer this method method over making the TextBox itself visible by modifying its access modifier because it gives you better encapsulation, ensuring you have control over how the textbox is used.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public string TextBoxValue
{
get { return textBox1.Text;}
set { textBox1.Text = value;}
}
}
And in the button click event of the first form you can just have code like:
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.TextBoxValue = "SomeValue";
form2.Show();
}
You can set "Modifiers" property of TextBox control to "Public"
Try this.. :)
Form1 f1 = (Form1)Application.OpenForms["Form1"];
TextBox tb = (TextBox)f1.Controls["TextBox1"];
tb.Text = "Value";
I know this was long time ago, but seems to be a pretty popular subject with many duplicate questions. Now I had a similar situation where I had a class that was called from other classes with many separate threads and I had to update one specific form from all these other threads. So creating a delegate event handler was the answer.
The solution that worked for me:
I created an event in the class I wanted to do the update on another form. (First of course I instantiated the form (called SubAsstToolTipWindow) in the class.)
Then I used this event (ToolTipShow) to create an event handler on the form I wanted to update the label on. Worked like a charm.
I used this description to devise my own code below in the class that does the update:
public static class SubAsstToolTip
{
private static SubAsstToolTipWindow ttip = new SubAsstToolTipWindow();
public delegate void ToolTipShowEventHandler();
public static event ToolTipShowEventHandler ToolTipShow;
public static void Show()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = true;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
public static void Hide()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = false;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
}
Then the code in my form that was updated:
public partial class SubAsstToolTipWindow : Form
{
public SubAsstToolTipWindow()
{
InitializeComponent();
// Right after initializing create the event handler that
// traps the event in the class
SubAsstToolTip.ToolTipShow += SubAsstToolTip_ToolTipShow;
}
private void SubAsstToolTip_ToolTipShow()
{
if (Vars.MyToolTipIsOn) // This boolean is a static one that I set in the other class.
{
// Call other private method on the form or do whatever
ShowToolTip(Vars.MyToolTipText, Vars.MyToolTipX, Vars.MyToolTipY);
}
else
{
HideToolTip();
}
}
I hope this helps many of you still running into the same situation.
In the designer code-behind file simply change the declaration of the text box from the default:
private System.Windows.Forms.TextBox textBox1;
to:
protected System.Windows.Forms.TextBox textBox1;
The protected keyword is a member access modifier. A protected member is accessible from within the class in which it is declared, and from within any class derived from the class that declared this member (for more info, see this link).
I also had the same doubt, So I searched on internet and found a good way to pass variable values in between forms in C#, It is simple that I expected. It is nothing, but to assign a variable in the first Form and you can access that variable from any form. I have created a video tutorial on 'How to pass values to a form'
Go to the below link to see the Video Tutorial.
Passing Textbox Text to another form in Visual C#
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
TextBox txt = (TextBox)frm.Controls.Find("p1c1val", true)[0];
txt.Text = "foo";
}