C# - variable reference does not exist in the current context - c#

I have this code in the main window class where I declare some values to put in a ListForTesting list and make the tests appear in a combobox. Later there is another combobox that depends on the first on which I present you the code down bellow:
It may be worth to mention that I am completely new to C#. Only coded in VBA. I'm a mechanical engineer, not software :)
Main Window code
public MainWindow()
{
InitializeComponent();
grid_projectConfig.Visibility = Visibility.Collapsed;
grid_projectOverview.Visibility = Visibility.Collapsed;
grid_test.Visibility = Visibility.Collapsed;
grid_reports.Visibility = Visibility.Collapsed;
//ListForTesting holds the hardcoded set of tests and manoeuvres
List<HelpClass.TestID> ListForTesting = new List<HelpClass.TestID>();
//TestObject holds the test name, ID and all the manoeuvres related to it
HelpClass.TestID TestObject = new HelpClass.TestID();
TestObject.testName = "Steady State";
TestObject.ID = 0;
//Manoeuvre holds the manoeuvre name and its ID
TestObject.Manoeuvres = new List<HelpClass.ManoeuvresID>();
HelpClass.ManoeuvresID Manoeuvre = new HelpClass.ManoeuvresID();
Manoeuvre.manName = "30 kph";
Manoeuvre.manID = 0;
//add the Manoeuvre to the TestObject
TestObject.Manoeuvres.Add(Manoeuvre);
//create new Manoeuvre
Manoeuvre = new HelpClass.ManoeuvresID();
Manoeuvre.manName = "50 kph";
Manoeuvre.manID = 1;
TestObject.Manoeuvres.Add(Manoeuvre);
//add the TestObject to the ListForTesting
ListForTesting.Add(TestObject);
//display the tests in a combobox
combobox_testType.ItemsSource = ListForTesting.Select(t => t.testName);
}
Second combobox code
public void combobox_testType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
combobox_testType.ItemsSource = ListForTesting[1].Manoeuvres.Select(t => t.manName);
}
this last line of code does not work because it tells me that it does not exist in the current context.

The problem is the scope of the variable ListForTesting: by declaring it inside your MainWindow constructor you limit its visibility to that method.To allow to access ListForTesting from another method in your class (i.e.: combobox_testType_SelectionChanged) you have to declare it as a class-level variable like so:
public class MainWindow : Window
{
private List<HelpClass.TestID> ListForTesting; // Variable declaration
public MainWindow()
{
// code
ListForTesting = new List<HelpClass.TestID>(); // Initialization
// code
}
}

the variable ListForTesting is in the scope of the constructor. You need to move the variable out of there for it to be accessible elsewhere in the class.
List<HelpClass.TestID> ListForTesting;
public MainWindow()
{
...
ListForTesting = new List<HelpClass.TestID>();
...
}

Related

Not able to set "SelectedValue" in Combobox bound with enum

I want to set default value (rather than first one) in combobox through SelectedItem/SelectedText/SelectedValue (from any one way).
I have tried to resolve it through many different ways. Like I have set enum to Key Value Pair. Tried to use "SelectedIndex". It is showing '-1' while debugging. In other "selected*" options, value is 'null'. I do not know what is happening. I have attached code. Please take a look and help me to resolve it. Thank you.
ComboBox cmbxType= new ComboBox();
cmbxType.FormattingEnabled = true;
cmbxType.DropDownStyle = ComboBoxStyle.DropDownList;
cmbxType.Margin = new Padding(3, 6, 3, 3);
cmbxType.Name = "cmbxType";
cmbxType.Size = new System.Drawing.Size(200, 28);
cmbxType.TabIndex = 1;
cmbxType.DataSource = Enum.GetValues(typeof(StateType));
cmbxType.SelectedIndexChanged += new System.EventHandler(cmbxType_SelectedIndexChanged);
cmbxType.ValueMember = (workflowRows).ToString();
cmbxType.SelectedValue = 2
PS: I am creating this combobox after creating form and the problematic case is with enum only.
According to this Stack Overflow question you can only set the selected item after the data bindings are assigned. If you select the item when the OnLoad event occures it should work. Below is a working example.
using System;
using System.Windows.Forms;
namespace WindowsFormsApp
{
static class Program
{
internal enum StateType
{
State1,
State2,
State3
}
internal class DemoForm : Form
{
ComboBox cmbxType = new ComboBox();
public DemoForm()
{
cmbxType.DataSource = Enum.GetValues(typeof(StateType));
Controls.Add(cmbxType);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
cmbxType.SelectedItem = StateType.State3;
}
}
[STAThread]
static void Main()
{
Application.Run(new DemoForm());
}
}
}

ListBox doesn't show collection of objects in C#

EDITED! WORKING CODE
I have the following class:
class Medic
{
private readonly int codM;
private string numeM;
private string specialitate;
//i have a constructor and properties with get and set, correctly written
}
I added 3 textBoxes to the form to be filled, each one related to one of the class attributes.
After this i have a button, and if all 3 textbox fields are correctly completed, a new class object is created.
This object will be added to a List. And this list of objects I want to be displayed in a listBox, and be updated as I add new objects.
Also, I want to have 2 objects already in the List and displayed in the listBox as I run the program, created in the code I mean, not using the textBoxes, and the new entered objects to come after these. I barely know where to write the code to create these 2 objects, same as where is ok to create and populate the List of objects or to write the code to bind this list into the ListBox;
public partial class Form1 : Form
{
List<Medic> listaMedici = new List<Medic>();
Medic m1 = new Medic(0, "ion", "endocrinologie");
public Form1()
{
InitializeComponent();
listaMedici.Add(m1);
}
private void button1_AddObject_Click(object sender, EventArgs e)
{
if (textBox1_cod.Text == "")
errorProvider1.SetError(textBox1_cod, "Introduceti codul medicului!");
else if (textBox2_nume.Text == "")
errorProvider1.SetError(textBox2_nume, "Introduceti numele medicului");
else if (Regex.IsMatch(textBox2_nume.Text, #"^[ a-zA-Z]+$") == false)
errorProvider1.SetError(textBox2_nume, "Numele contine doar litere si spatii");
else if (textBox3_specialitate.Text == "")
errorProvider1.SetError(textBox3_specialitate, "Introduceti specialitatea medicului");
else
{
try
{
Medic medic = new Medic(Convert.ToInt32(textBox1_cod.Text), textBox2_nume.Text, textBox3_specialitate.Text);
foreach (Medic m in listaMedici)
{
if (textBox1_cod.Text == m.CodM.ToString())
{
throw new Exception("Codul contractului incalca proprietatea de unicitate. Introduceti un cod unic");
textBox1_cod.Clear();
}
}
listaMedici.Add(medic);
listBox1_medici.DataSource = new ObservableCollection<Medic>(listaMedici);
listBox1_medici.DisplayMember = nameof(Medic.NumeM);
listBox1_medici.ValueMember = nameof(Medic.CodM);
listBox1_medici.SelectedIndex = 0;
MessageBox.Show("ADDED!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
errorProvider1.Clear();
textBox1_cod.Clear();
textBox2_nume.Clear();
textBox3_specialitate.Clear();
}
}
}
private void listBox1_medici_SelectedIndexChanged(object sender, EventArgs e)
{
}
The display member should be the name of the property to display, not a string property. Reflection is used to look for a property of the name of the display member. For example if your medic.NumeM value is "Hello" WPF will look for a property named "Hello", retrieve the value of the property and display it in the listbox.
In your case the code should be: listBox1_medici.DisplayMember = "NumeM";

Pass number of the button in the name of the variable

I have this lines of code:
button0.BorderBrush = new SolidColorBrush(Colors.Red);
button1.BorderBrush = new SolidColorBrush(Colors.Red);
button2.BorderBrush = new SolidColorBrush(Colors.Red);
...
How can I make correct this:
(button + "numberOfButton").BorderBrush = new SolidColorBrush(Colors.Red);
Any time you find yourself with variables like this:
button0
button1
button2
etc...
What you should have is an array. If the controls themselves are already static on the form, then you can simply build the array when loading the form. Something like this:
public class MyForm : Form
{
private IEnumerable<Button> myButtons;
public MyForm()
{
myButtons = new List<Button>
{
button0, button1, button2 // etc...
};
}
// etc...
}
Then when you need to loop over the buttons, you simply loop over the collection:
foreach (var button in myButtons)
button.BorderBrush = new SolidColorBrush(Colors.Red);
If you need to reference the collection elements by index, use an IList<> instead of an IEnumerable<>. If you need to do more complex things, use any number of collection types.
You can find it by name with method Control.Find:
var button = this.Control.Find("button0", true).FirstOrDefault();
But better to store buttons in array and get them by index:
var buttons = new Control[10];
buttons[0] = button0;
...

How to Give back a DataGridView in Winforms

So, I have a project in which I allow editing of a DatagridView in a separate Form. I pass in the DatagridView object and its parent container to the constructor of the new Form.
This works well and I can edit the grid that way. But when I try to give it back by changing its parent back to the original form, I get this error :
Cannot convert type 'System.Windows.Forms.MenuItem' to 'System.Windows.Forms.Control'
Now both MenuItem, and Manual Entry directly inherit from Form.
Here is my code that takes the DataGridView from the original form (which works correctly)
public partial class ManualEntry : Form
{
private Data d;
DataGridView DataView;
MenuItem mi;
public ManualEntry(DataGridView ExcelDisplay, Data d, MenuItem menuItem)
{
InitializeComponent();
//Take the Datagridview from the MenuItem.
DataView = ExcelDisplay;
DataView.Parent = this;
mi = menuItem;
this.d = d;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(15, 76);
this.DataView.Size = new System.Drawing.Size(237, 211);
this.DataView.TabIndex = 5;
this.DataView.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataView_CellContentClick);
}
Now here is me trying to give it back. and of course it produces the error above.
private void FinishButton_Click(object sender, EventArgs e)
{
//move the datagridview back to the original form and give its old size,shape, and position back.
DataView.Parent = mi;
this.DataView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.DataView.Location = new System.Drawing.Point(12, 167);
this.DataView.Name = "ExcelDisplay";
this.DataView.Size = new System.Drawing.Size(250, 256);
this.DataView.TabIndex = 7;
this.Close();
}
I have also tried casting which does not work either.
DataView.Parent = (System.Windows.Forms.Control)mi;
Update
This shows that MenuItem is a Form as well.
public partial class MenuItem : Form
{
This shows that MenuItem is a Form as well.
Well, you have not convinced the compiler. You can tell from the error message that it thinks that your "mi" variable is a System.Windows.Forms.MenuItem. Do not use .NET class names for your own types, that just makes your life harder to troubleshoot bugs like this. Don't use variable names like "d" either. Choosing good names is a Very Important programmer's job.
The proper way is to preserve the control's Parent property so you can set it back. Roughly:
public partial class ManualEntry : Form
{
private Data DataViewData;
private DataGridView DataView;
private Point DataViewLocation;
private Control DataViewParent;
public ManualEntry(DataGridView ExcelDisplay, Data data)
{
InitializeComponent();
this.DataViewData = data;
this.DataView = ExcelDisplay;
this.DataViewLocation = ExcelDisplay.Location;
this.DataViewParent = ExcelDisplay.Parent;
this.DataView.Parent = this;
// etc...
}
protected override void OnFormClosing(FormClosingEventArgs e) {
base.OnFormClosing(e);
if (!e.Cancel) {
DataView.Parent = this.DataViewParent;
DataView.Location = this.DataViewLocation;
// etc..
}
}
}

Having trouble getting parent class call child class method - reflection used

Problem: Program flow is not going to the child class implementation of ValidateDynData when I call ValidateDynData in my parent class.
I create my instance of my class using reflection. When I invoke a method in the child class from another project, it winds up in the correct method in the child class (and not parent's same-name method), so it seems like that is set up correctly.
This is what the reflection part looks like in my other project/class:
**Note 3/7/2013: I added more info so you can get the general feel for this. It gets the number of boxes, loops thru the number of boxes, and for each box, creates a control and adds a tab to the form. This is the main CTool visual studio project and is a class in the project, which is a form. When I press a button on the form, with the info (selected) on which child class I'm going to be creating later, it goes to this method , CreatTabs():
cb = new CB();
int errValue = cb.FindUsbHid(ref HWndBoxID); //see how many boxes there are
if (errValue == 0 && HWndBoxID[0, 1] != 0)
{
for (int i = 0; i < cb.cbInfos.Length; i++)
{
if (controls[i] == null)
{
CB cb1 = new CB(); //need one for each box found or concurrent programming will fail
errValue = cb1.FindUsbHid(ref HWndBoxID); //need to do for each box to get all info
/////////////////////////////////////////
if (errValue == 0)
{
_assembly = Assembly.LoadFrom(programDll);
_type = _assembly.GetType("CrWriter.PC");
_objectInstance = Activator.CreateInstance(_type);
_parameters = new Object[] { cb1, programDll, templateArr, itsDll, cert, i, cb1.cbInfos[i].boxID };
controls[i] = new Control();
//The following lands in my child's GetPC method
//My parent also has a method called GetPC and that is called from the child.
//Then, most of the program flow is in the parent until I need to call ValidateDynData,
//discussed below
controls[i] = (Control)_type.InvokeMember("GetPC", BindingFlags.Default | BindingFlags.InvokeMethod, null, _objectInstance, _parameters);
controls[i].Dock = DockStyle.None;
this.Controls.Add(controls[i]);
TabPage newPage = new TabPage(string.Format("{0}:{1}", cb1.cbInfos[i].usbHandle, cb1.cbInfos[i].boxID));
Console.WriteLine("frmUserForm::CreateTabs - Making new tab with cb.cbInfos[i].usbHandle:" + cb1.cbInfos[i].usbHandle + " and cb.cbInfos[i].boxID:" + cb1.cbInfos[i].boxID);
InitializeControls(controls[i]);
tabCtrlMain.Size = controls[i].Size;
tabCtrlMain.Width += 20;
tabCtrlMain.Height += 100;
this.Width = tabCtrlMain.Width + 20;
this.Height = tabCtrlMain.Height + 50;
newPage.Controls.Add(controls[i]);
tabCtrlMain.TabPages.Add(newPage);
} //no err for this cb
} //controls not null
} //for all cbInfo's
}//if no err in general finding out how many cb's
this.ResumeLayout();
}
Since my Invocation of GetPC lands in the child class and not the parent, it must be created correctly. So I'm not sure why it's not landing in the correct ValidateDynData method. Maybe I need to cast my object to the programDll somehow. When I run the program and inspect the _objectInstance it could be a problem:
variable..................................................value
base: {GenericCrWriter.GenericPC} ......CrWriter.PC
baseInst: ................................................GenericCrWriter.GenericPC
But then, the _assembly is referring to Ko/PC and not Generic/GenericPC.
Also, my _assembly.GetType looks good. My Generic/parent doesn't have anything named CrWriter.PC
I'm trying to use the child class method instead of the parent class for some child class cases. For some reason, I get to the parent class method, but it never gets to the override in the child. Any ideas why? I've been referring to Calling child class method from parent
but it's not getting to the child's method.
In my PC.cs of the child class (Ko):
**Note 3/8/2013: PC.cs is in the Ko visual studio project. **this contains a form that is displayed
**Note 3/7/2013: This is a separate visual studio project named after the child, let's call it Ko. The important class here is PC.cs. It doesn't do much except pass data to the parent, provide it's custom textBoxes and their names, validate data entered later in the parent's form. Most of the flow is in the parent, otherwise. I'm adding GetPC, setProgramName, setDTF methods.
public partial class PC : GenericPC
{
String childDllName = ""; //I just added this recently but it doesn't seem useful
GenericPC baseInst = new GenericPC();
public Control GetPC(USB_Comm.CB cbInst, string dllSel, TemplateHApp.Templates.TEMPL[] templ, string dll, SC.SC.SITE c0, int slaveIndex, int BoxID)
{
childDllName = dll;
//call parent class methods
setProgramName();
setDTF();
ProcessDynData();
return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
}
public void setProgramName()
{
Console.WriteLine("Ko did stuff");
//Update label on form
var f = new F(); //F is a class in child class containing more info on it
string temp = f.GetProgramName();
baseInst.setProgramName(temp); //this is displayed on parent's form
}
public void setDTF()
{
var f = new F();
string temp = f.DTF();
baseInst.setDTF(temp); //this is displayed on parent's form
}
private void ProcessDynamicData()
{
Console.WriteLine("Ko PC::ProcessDynamicData");
Label lbl_dynData0 = new Label();
Label lbl_dynData1 = new Label();
lbl_dynData0.Text = "AT .";
lbl_dynData1.Text = "VL .";
lbl_dynData0.Location = new Point(57, 25);
lbl_dynData1.Location = new Point(57, 45);
Label[] lbl_dynData_Arr = new Label[4];
lbl_dynData_Arr[0] = lbl_dynData0;
lbl_dynData_Arr[1] = lbl_dynData1;
TextBox tb_dynData0 = new TextBox();
TextBox tb_dynData1 = new TextBox();
tb_dynData0.Location = new Point(67, 25);
tb_dynData1.Location = new Point(67, 45);
tb_dynData0.Size = new Size(151,22);
tb_dynData1.Size = new Size(151, 22);
TextBox[] tb_dynData_Array = new TextBox[4];
tb_dynData_Array[0] = tb_dynData0;
tb_dynData_Array[1] = tb_dynData1;
PC pc = this; //Tried adding this to get past problem but it's not turned out useful
//I think the way I access parent class from child is the problem of why flow in
//parent class isn't reaching overridden method in child when called:
baseInst.addDynamicDataTextBoxes(tb_dynData_Array, lbl_dynData_Arr, childDllName, pc);
}
public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{ //I added more info here, but it's probably too much info 3/7/2013
Console.WriteLine("Ko PC::ValidateDynData");
result = -610;
//AT
if ((Convert.ToInt16(tb_dynData_Array[0].Text) >= 1) && (Convert.ToInt16(tb_dynData_Array[0].Text) <= 99))
result = 0;
//VL
if (result == 0)
if ((Convert.ToInt16(tb_dynData_Array[1].Text) >= 69) && (Convert.ToInt16(tb_dynData_Array[1].Text) <= 100))
result = 0;
else
result = -610;
}
In my GenericPC.cs of the parent class:
**Note 3/8/2013: GenericPC is in the Generic visual studio project.
**Note 3/7/2013 When the child class calls the parent class to initialize important data, the parent class shows it's form and fields (I think resume layout shows it). Next, we enter data on the form, including Ko's custom data, then we hit a button on the form (btn_Lock_Config_Click) and it needs to process and validate it's data. I added more methods to get the feel for flow. There are a ton more methods in parent than child (not shown), including try/catch, etc.
//base
public partial class GenericPC : UserControl
{
//class variables (wave your hands..too much info)
public Control GetPC(USB_Comm.CB cbInstance, string dllSelected, TemplateHApp.Templates.TEMPL[] template, string dll, SC.SC.SITE c0, int slaveIndex, int boxID)
{
cb = cbInstance;
SlaveIndex = slaveIndex;
createControls();
itsDll = dll;
templateArr = template;
return this; //return the control for the control array
}
//called from child class
public void setProgramName(string name)
{
Console.WriteLine("Generic setProgramName slaveIndex:" + SlaveIndex);
lbl_Program_Name.Text = name;
}
//called from child class
public void setDTF(string theDTF)
{
Console.WriteLine("Generic setDTF slaveIndex:" + SlaveIndex);
lbl_Program_Name.Text += " ";
lbl_Program_Name.Text += theDTF;
lbl_Program_Name.Refresh();
}
public void addDynamicDataTextBoxes(TextBox [] tb_dynData, Label [] lblTitle, String childName, Object child)
{
childHasDynamicData = true; //somebody's knocking
itsChildName = childName; //child name isn't turning out to be useful here
itsChild = child; //child isn't turning out to be useful here
Console.WriteLine("Generic addDynamicDataTextBoxes slaveIndex:" + SlaveIndex);
//Display what child wants
for (int i = 0; i < tb_dynData.Length; i++)
{
//assumes calling code knows real estate and planned for it
gb_dynamicData.Controls.Add(lblTitle[i]);
gb_dynamicData.Controls.Add(tb_dynData[i]);
}
itsEnteredDynamicData = tb_dynData; //nothing entered yet
}
private void btn_Lock_Config_Click(object sender, EventArgs e)
{
int status = 1;
Console.WriteLine("Generic btn_Lock slaveIndex:" + SlaveIndex);
//it does some flagging and data checking, etc.
status = processDynamicData();
}
private int processDynData()
{
int returnCode = 0; //I'm setting it to desired value for example
//processes data, puts it into data arrays, etc,
if ((returnCode >= 0) && childHasDynamicData)
ValidateDynData(itsEnteredDynamicData, ref returnCode);
//start here for problem...it never calls child method, as intended
}
public virtual void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{
Console.WriteLine("Generic::ValidateDynData passing off to child to validate special data");
}
Any ideas why it's not going to the child class implementation of ValidateDynData when I call ValidateDynData in my parent class? This is the only area in my code where I am trying to have a child class override a parent implementation, so I'm not sure if I'm doing something wrong?
I checked the correct version of Generic.dll is referenced in the child's project/class. I did a clean build in the child class. Any other binaries that should be checked? Is there something wrong with my reflection? Is there something wrong with my virtual/override use for ValidateDynData?
Update:
I've been looking at the code some more, and I get flow into the parent class by creating an instance of the parent/base class. So I think that's why I'm not getting into ValidateDynData that is overridden in the child class when I call it in parent. Is there another way to get to the parent's method without creating an instance of the parent?
GenericPC baseInst = new GenericPC();
return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
**Update 3/7/13:
It's also possible that the problem is that I press a button on the parent's form which starts a new thread and by doing this, it doesn't know about child class, so that's why flow doesn't get to child when I call ValidateDynData method.
Short answer: Just delete all that awful code and start over.
Longer answer:
// (1)
public partial class PC : GenericPC
{
// (2)
GenericPC baseInst = new GenericPC();
public Control GetPC(…)
{
…
// (3)
return baseInst.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
}
public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{
// (4)
…
}
}
Comments to marked lines of code:
At this point you declare PC as a descendant of GenericPC. So far so good.
Here you declare and instantiate a completely disparate instance of GenericPC which has nothing to do with the instance of PC you are working with.
You call GetPC, a method of an instance of PC, which in turns call GetPC in that completely disparate instance of GenericPC; nothing in common with the original PC instance!
Finally, you expect control flow to end up the original PC instance; but that won't ever happen when, effectively, you all the time call methods of some silly GenericPC instance!
My recommendation is reading a book about object-oriented programming, that provides samples in C#. It seems you are even missing the point of inheritance, one of the basic concepts in OOP.
To fix it, you need to remove the declaration of baseInst, and replace all calls to baseInst's methods with the base keyword. Then your code will actually call methods declared in the ancestor class within the same instance. Also most methods shall be declared as virtual in GenericPC and you have to override them in PC.
public partial class PC : GenericPC
{
public override Control GetPC(…)
{
…
return base.GetPC(cbInst, dllSel, templ, dll, cert0, slaveIndex, BoxID);
}
public override void ValidateDynData(TextBox[] tb_dynData_Array, ref int result)
{
…
}
}

Categories

Resources