I am trying to store multiple values from numerous buttons so I can return values of two or more things e.g. if chocolate and vanilla clicked both prices and names can be returned. I will also need to make calculations on the data set later. Whenever I return the data only the most recent values return rather than all of those I have selected.
private void VanillaBtn_Click(object sender, RoutedEventArgs e)
{
items.Price = 450;
items.Name = "Vanilla"
}
private void ChocolateBtn_Click(object sender, RoutedEventArgs e)
{
items.Price = 500;
items.Name = "Chocolate";
}
This is my class, any help or tips would be appreciated.
class Items
{
private int thePrice;
private string theName;
public int Price
{
get
{
return thePrice;
}
set
{
thePrice = value ;
}
}
public string Name
{
get
{
return theName;
}
set
{
theName = value;
}
}
Keep a list of whatever was clicked.
private List<Items> selectedItems = new List<Items>();
So, every time something is clicked, you store the object in the list defined above.
private void VanillaBtn_Click(object sender, RoutedEventArgs e)
{
var newItem = new Items();
newItem.Price = 450;
newItem.Name = "Vanilla";
selectedItems.Add(newItem);
}
Related
I have two form:
the first one "FrmAddRecordOfNonComplianceQHSE" has in load event this code
private async void FrmAddRecordOfNonComplianceQHSE_Load(object sender, EventArgs e)
{
KeyPreview = true;
txtCreationDate.EditValue = DateTime.Today;
DataTable DDt = await qhse.GetLastQHSEOrderNumberRecordOfNonCompliance().ConfigureAwait(true);
string RatingNumber = DDt.Rows[0][0].ToString();
txtOrderNumber.Text = RatingNumber;
cmbDetecteurStructure.Properties.DataSource = await qhse.GetEmployeesByDepartmentID(Program.FK_Department).ConfigureAwait(true);
cmbDetecteurStructure.Properties.DisplayMember = "Nom et Prénom";
cmbDetecteurStructure.Properties.ValueMember = "Matricule";
cmbRelevantStructure.Properties.DataSource = await qhse.Get_Department().ConfigureAwait(true);
cmbRelevantStructure.Properties.DisplayMember = "Département";
cmbRelevantStructure.Properties.ValueMember = "ID_Department";
}
and I have this code also
private void cmbRelevantStructure_Closed(object sender, ClosedEventArgs e)
{
BeginInvoke(new MethodInvoker(() => { cmbRelevantEmployee.EditValue = null; }));
}
private async void cmbRelevantEmployee_Enter(object sender, EventArgs e)
{
try
{
cmbRelevantEmployee.Properties.DataSource = await qhse.GetManagerByDepartmentID(Convert.ToInt32(cmbRelevantStructure.EditValue, CultureInfo.CurrentCulture)).ConfigureAwait(true);
cmbRelevantEmployee.Properties.DisplayMember = "Nom et Prénom";
cmbRelevantEmployee.Properties.ValueMember = "Matricule";
}
catch { }
}
and about the second form "FrmRecordOfNonComplianceQHSE" I have this code
FrmAddRecordOfNonComplianceQHSE frmQHSE = new FrmAddRecordOfNonComplianceQHSE();
and on DoubleClick of gridView1 I have this code
private async void gridView1_DoubleClick(object sender, EventArgs e)
{
//frmQHSE.cmbDetecteurStructure.Properties.DataSource = null;
frmQHSE.cmbDetecteurStructure.EditValue = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "FKDetecteur");
frmQHSE.txtCreationDate.EditValue = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "CreationDate");
frmQHSE.txtOrderNumber.Text = string.Empty;
frmQHSE.txtOrderNumber.Text = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "OrderNumber").ToString();
frmQHSE.cmbRelevantStructure.EditValue = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "RelevantDepartment");
frmQHSE.cmbRelevantEmployee.Enter += new EventHandler(cmbRelevantEmployee_Enter);
frmQHSE.cmbRelevantEmployee.EditValue = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "FKRelevant");
if (frmQHSE == null || frmQHSE.IsDisposed)
frmQHSE = new FrmAddRecordOfNonComplianceQHSE();
frmQHSE.ShowDialog();
}
and I have this code also
private async void cmbRelevantEmployee_Enter(object sender, EventArgs e)
{
try
{
frmQHSE.cmbRelevantEmployee.Properties.DataSource = await qhse.GetManagerByDepartmentID(Convert.ToInt32(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "RelevantDepartment"), CultureInfo.CurrentCulture)).ConfigureAwait(true);
frmQHSE.cmbRelevantEmployee.Properties.DisplayMember = "Nom et Prénom";
frmQHSE.cmbRelevantEmployee.Properties.ValueMember = "Matricule";
}
catch { }
}
Now when I DoubleClick on gridView1 row the first form open but the controls get the values from the load event of that form not the values of gridView1 of my second form.
How can solve this problem ?.
Thanks in advance.
Either use data binding and assign an object to DataSource or assign values to the controls, but do not mix both approaches.
I assume that GetManagerByDepartmentID now returns a DataTable or something like this, since you have display member names with spaces. Create data classes instead. This makes it easier to manipulate the data. Something like this
public class Employee
{
public string NomPrénom { get; set; }
public int Matricule { get; set; }
public string Département { get; set; }
public int ID_Department { get; set; }
...
}
Now, you can let GetManagerByDepartmentID return an Employee object. Your form binds to an Employee object and your grid can bind to an Employee object. Or at least you can create and fill such an object manually and assign it to the DataSource of the first form.
private async void gridView1_DoubleClick(object sender, EventArgs e)
{
var emp = new Employee {
FKDetecteur = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "FKDetecteur"),
CreationDate = gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "CreationDate"),
OrderNumber gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "OrderNumber").ToString(),
....
};
frmQHSE.EmployeeBindingSource.DataSource = emp;
frmQHSE.ShowDialog();
}
Use BindingSourcees in conjunction with object data sources on your from. This allows you to set DisplayMembers and ValueMembers in the forms designer.
I have to select one brand of moto. If i select "KTM", i want to get Ktm's motos. If i select "HVA", i want HVA's motos. Etc ..
I have a List of models with all models, and in function what i select, i want to add models by this brand and return this in my ComboBox2.
Modele.cs :
class Modele
{
public string NomModele;
public static List<Modele> lesModeles = new List<Modele>() {
// Husqvarna
new Modele() { NomModele = "TE"},
new Modele() { NomModele = "FE"},
// KTM
new Modele() { NomModele = "EXC"},
new Modele() { NomModele = "EXC-F"}
};
public Modele() { }
public Modele(string NomModele)
{
this.NomModele = NomModele;
}
}
Main.cs :
namespace SuiviEntretien
{
public partial class SuiviEntretien : Form
{
public SuiviEntretien()
{
InitializeComponent();
this.lesMarques.Items.AddRange(Marque.lesMarques.Select(x => x.NomMarque).ToArray());
this.lesModeles.Items.AddRange(Modele.lesModeles.Select(x => x.NomModele).ToArray());
}
private void SuiviEntretien_Load(object sender, EventArgs e)
{
}
private void SauvegarderMoto_Click(object sender, EventArgs e)
{
try
{
Moto maMoto = new Moto(
maMarque.Text = lesMarques.SelectedItem.ToString(),
monModele.Text = lesModeles.SelectedItem.ToString()
);
MessageBox.Show("Moto enregistrée avec succès !", "Information");
tabControl1.SelectTab(MaMoto);
}
catch(Exception)
{
MessageBox.Show("Il manque des informations !", "Information");
}
}
}
}
Thanks for further help.
The following answer has been made with some assumptions, those being:
-You have a ComboBox that contains values, when a value is selected another ComboBox needs to re-populate itself with a new list of data.
Depending on the scale of this problem I would recommend two solutions. Move your data into a relational database and access it accordingly, then populate your first ComboBox as a list of all main keys. (One to many methodology) then populate your second ComboBox according to the first ComboBox value.
Assuming you want to build your list dynamically and want to avoid a database then simply use functionality based on if the ComboBox changes.
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e) {
if (ComboBox1.Text == "KTM")
{
// Populate ComboBox2 with KTM data.
}
else
{
// Populate ComboBox2 with some other data.
}
}
This should help you out.
I'm having strange issues with the check box control in C# .Net
My code below shows all logic that is required - _itemsChecked is a private dictionary containing all of the _fixtures and whether they are true or false (checked or un checked)
What I want is to be able to search my check list whilst retaining those which have been checked previously. If a checked item is included in the search results I want it to be checked.
The code nearly works! But for some reason boxes are randomly checked here and there, and it appears to work through debug but when the screen returns to the control it then hasn't worked.
Sure I'm missing something very simple.
My logic is:
DataSource includes those which match the typed search query,
Iterate through this list and check if the Guid is true in the dictionary.
If it is true then we set it as checked.
Hope I have provided adequate information.
Many thanks in advance.
private void searchTextBox_KeyUp(object sender, EventArgs e)
{
lst.DataSource = _fixtures
.OrderBy(f =>
f.Description)
.Where(f =>
f.Description.ToLower().Contains(searchFixturesTextBox.Text.ToLower()))
.ToList();
lst.DisplayMember = "Description";
for (var i = 0; i < lst.Items.Count; i++)
if(_itemsChecked.Contains(new KeyValuePair<Guid, bool>(((Fixture)lst.Items[i]).Guid, true)))
lst.SetItemChecked(i, true);
}
void lst_ItemCheck(object sender, ItemCheckEventArgs e)
{
var selectedItem = ((ListBox) sender).SelectedItem as Fixture;
if (selectedFixtureItem != null)
_itemsChecked[selectedItem.Guid] = e.CurrentValue == CheckState.Unchecked;
}
So I put this together from a few examples I found. The majority of the work came from How do I make a ListBox refresh its item text?
public class Employee
{
public string Name { get; set; }
public int Id { get; set; }
public bool IsChecked { get; set; }
public override string ToString()
{
return Name;
}
}
public partial class Form1 : Form
{
// Keep a bindable list of employees
private BindingList<Employee> _employees;
public Form1()
{
InitializeComponent();
// Load some fake employees on load
this.Load += new EventHandler(Form1_Load);
// Click once to trigger checkbox changes
checkedListBox1.CheckOnClick = true;
// Look for item check change events (to update there check property)
checkedListBox1.ItemCheck +=
new ItemCheckEventHandler(CheckedListBox_ItemCheck);
}
// Load some fake data
private void Form1_Load(object sender, EventArgs e)
{
_employees = new BindingList<Employee>();
for (int i = 0; i < 10; i++)
{
_employees.Add(new Employee()
{ Id = i, Name = "Employee " + i.ToString() });
}
// Display member doesnt seem to work, so using ToString override instead
//checkedListBox1.DisplayMember = "Name";
//checkedListBox1.ValueMember = "Name";
checkedListBox1.DataSource = _employees;
// Another example databind to show selection changes
txtId.DataBindings.Add("Text", _employees, "Id");
txtName.DataBindings.Add("Text", _employees, "Name");
}
// Item check changed, update the Employee IsChecked property
private void CheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox clb = sender as CheckedListBox;
if (clb != null)
{
Employee checked_employee = clb.Items[e.Index] as Employee;
if (checked_employee != null)
{
checked_employee.IsChecked = (e.NewValue == CheckState.Checked);
}
}
}
// Just a simple test that removes an item from the list, rebinds it
// and updates the selected values
private void btnChangeList_Click(object sender, EventArgs e)
{
_employees.RemoveAt(1);
checkedListBox1.DataSource = _employees;
for (var i = 0; i < checkedListBox1.Items.Count; i++)
{
Employee employee_to_check = checkedListBox1.Items[i] as Employee;
if (employee_to_check != null)
{
checkedListBox1.SetItemChecked(i, employee_to_check.IsChecked);
}
}
}
}
I've been puzzling over this one for a few days now and it's got me pretty beaten, but to be honest I'm not all that experienced yet and I'm having trouble with DataGridView - which seems a common topic.
public partial class frmMain : Form
{
ServerConnection sabCom;
private BindingSource jobSource = new BindingSource();
private void timer1_Tick(object sender, EventArgs e)
{
if (bgUpdateThread.IsBusy == false)
{
bgUpdateThread.RunWorkerAsync(sabCom);
}
}
}
private void frmMain_Load(object sender, EventArgs e)
{
timer1.Interval = 3000;
timer1.Start();
}
private void bgUpdateThread_DoWork(object sender, DoWorkEventArgs e)
{
ServerConnection s = e.Argument as ServerConnection;
s.update();
e.Result = s;
}
private void bgUpdateThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.sabCom = e.Result as ServerConnection;
if (dgvQueueFormatted == false)
{
dgvQueue_Init(); //Applies formatting and loads column width. Inits data sources.
}
else
{
dgvQueue_Update();
}
}
private void dgvQueue_Update()
{
dgvQueue.Refresh();
}
private void dgvQueue_Init()
{
try
{
jobSource.DataSource = sabCom.queue.jobs;
dgvQueue.DataSource = jobSource;
try
{
//Apply saved column spacing to the dgvQueue
//Uses reflection to set dgvQueue to DoubleBuffer
}
catch
{ }
}
catch
{ }
}
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
//Saves information about the dgvQueue on shutdown.
}
Queue Class:
public class Queue
{
private string _status;
public string status { get { return _status; } set { _status = value; } }
private string _eta;
public string eta { get { return _eta; } set { _eta = value; } }
private List<Job> _jobs;
public List<Job> jobs
{
get
{
return _jobs;
}
set
{
_jobs = value;
}
}
private List<string> _categories;
public List<string> categories { get { return _categories; } set { _categories = value; } }
private XmlDocument xmld;
private ServerConnection m_parent;
private XmlNodeList _xmljobs;
public Queue(ServerConnection srvConn)
{
//fetch the Queue xml
m_parent = srvConn;
xmld = new XmlDocument();
_jobs = new List<Job>();
}
public void update()
{
updateXml();
updateQueue();
updateJobs();
}
private void updateXml()
{
//Loads xml file into xmld
}
private void updateQueue()
{
XmlNodeList elements = xmld.SelectNodes("queue");
foreach (XmlNode element in elements)
{
_status = element.SelectSingleNode("status").InnerText;
_eta = element.SelectSingleNode("eta").InnerText;
}
}
private void updateJobs()
{
_xmljobs = xmld.SelectNodes("queue/job");
jobs.Clear();
foreach (XmlNode xmljob in _xmljobs)
{
Job t_job;
_status = xmljob.SelectSingleNode("status").InnerText;
_eta = xmljob.SelectSingleNode("eta").InnerText;
//Create temp job to match against list.
t_job = new Job(_status, _eta);
jobs.Add(t_job);
}
}
Job class: In reality it holds around 30 values of varying types, but they're all in the same format:
public class Job
{
private int _status;
public int status { get { return _status; } set { _status = value; } }
private string _eta;
public string eta { get { return _eta; } set { _eta = value; } }
public Job(string status, string eta)
{
_status = status;
_eta = eta;
}
}
When interacting with the DataGridView I get the error:
The following exception occured in the DataGridView:
System.IndexOutOfRangeException: Index does not have a value.
at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
at System.Windows.Forms.DataGridViewDataConnection.GetError(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)
And when entering the debugger it's triggered on the initial Application.Run(new frmMain(). What on earth am I doing wrong? The program still functions and updates normally but I can't even handle the event to suppress the default error message!
Edit - Answer!
Instead of clearing the list and re-creating it, just updating the values within it works better. For the moment I have this code:
t_job = _jobs.FirstOrDefault(c => c.nzo_id == t_nzo_id);
if (t_job == null) //Job not in list, insert
{
t_job = new Job(t_status, i_index, t_eta, i_timeLeft, t_age, i_mbleft, i_mb, t_filename, i_priority, t_category, i_percentage, t_nzo_id, this);
jobs.Add(t_job);
}
else //update object in current list
{
jobs[t_job.Index].status = t_status;
jobs[t_job.Index].priority = i_priority;
jobs[t_job.Index].category = t_category;
jobs[t_job.Index].percentage = i_percentage;
jobs[t_job.Index].timeleft = i_timeLeft;
jobs[t_job.Index].mbleft = i_mbleft;
}
Which prevents it!
The problem seems to be that with a refresh interval of say 1 second, while the user is scrolling or trying to access the fields of the data the data is constantly being removed and readded.
This causes the binding to to call try call a value that it thinks might still be there, but isn't and that is why you are getting the index out of range exception
The first thing I would suggest doing is in your updateJobs method as well as all the other lists that are refreshed like the queue list, instead of clearing the list everytime is first checking to see if the job from the xml exists in the current job list, if it does then you can change the current values if the value has changed otherwise do nothing.
To check if the job exists it is as easy as:
t_job = _jobs.FirstOrDefault(c => c.Filename == t_filename);
This will return a null if the job does not exist, I would assume filename might not be unique, so might want to change it so that it really is unique i.e.
t_job = _jobs.FirstOrDefault(c => c.Filename == t_filename && c.nzo_id == t_nzo_id);
One thing you will now have to cater for is that old jobs won't be automatically removed, so whenever a new history job is added, first check to see if it exists in the queue and then remove it there before adding it to the history list.
so change your properties to be:
public int Index
{
get { return _index; }
set
{
if (_index != value)
_index = value;
}
}
instead of:
public int Index { get { return _index; } set { _index = value; } }
The other thing is that try catch exceptions are expensive, so instead of having:
try { i_percentage = double.Parse(t_percentage); } catch { }
because you know that if there is a value it is going to be a double, you can change it to:
if (!string.IsNullOrEmpty(t_percentage))
i_percentage = double.Parse(t_percentage);
now if you don't know if the value in t_percentage is going to be a double you can use a try-parse:
if (!string.IsNullOrEmpty(t_percentage))
double.TryParse(t_percentage,out i_percentage);
This way you avoid the overhead caused by an exception. This might be micro-optimizing and is not always neccessary if it doesn't actually cause a problem, but given that you can have hundreds of jobs, each with 10 or so properties refreshing everysecond, things can actually get noticeably slower if even 2 of the 10 properties throws an exception.
One more thing, after your backgroundworker is completed, in the method: dgvQueue_Update() you are calling the ResetBindings(true); this causes your whole datagrid to refresh instead of just the individual items.
try changing it to:
for (int i = 0; i < jobSource.List.Count; i++)
jobSource.ResetItem(i);
The difference is this:
this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, itemIndex));
compared to when you say ResetBindings:
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
The follwing code works well working for lvwResult, but how can I display the results in listbox1?
I just want to use listbox1 only, instead of lvwResult.
private void btnBrowse_Click(object sender, System.EventArgs e)
{
folderBrowserDialog1.ShowDialog();
if (folderBrowserDialog1.SelectedPath != "")
{
txtDirectory.Text = folderBrowserDialog1.SelectedPath;
}
}
private void btnClose_Click(object sender, System.EventArgs e)
{
this.Close ();
}
private void btnSearchNow_Click(object sender, System.EventArgs e)
{
MLSecurityFinder lSecFinder = new MLSecurityFinderClass ();
int iCounter = 0;
lvwResult.Items.Clear ();
lSecFinder.bScanSubDirectories = chkSubfolders.Checked;
try
{
lSecFinder.FindSecurity (txtSymbol.Text, txtDirectory.Text);
while (lSecFinder.bSecLeft)
{
ListViewItem lItem = lvwResult.Items.Insert (iCounter, lSecFinder.SecName);
lItem.SubItems.Add (lSecFinder.SecSymbol);
lItem.SubItems.Add (lSecFinder.SecFileName);
lSecFinder.FindNextSecurity();
iCounter++;
}
}
catch (System.Runtime.InteropServices.COMException ComEx)
{
//MessageBox.Show (ComEx.Message);
}
finally
{
lSecFinder.DestroySearchDialog ();
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
List boxes don't support multiple columns, unless you're planning on owner-drawing your listbox items. So you'll need to start by deciding how you're going to map your old multi-column data to a single string. Let's say, for the sake of argument, that you decide to combine the used-to-be-columns with commas, so that each of your listbox items would look like "SecName,SecSymbol,SecFileName".
That's the only part that's likely to be at all mysterious. From here, it's just like solving any other problem. You want to replace usages of lvwResult with usages of listbox1? Sounds like a job for search-and-replace to me. Then fix whatever doesn't compile. The code that builds your columns (SubItems) definitely won't compile, but by this point, you will have already decided what to do with that, so it's just a matter of writing code.
Here is just a sample on adding items to the listbox.
public class SampleData {
public string Name { get; set; }
public int Id { get; set; }
}
Now you have the code of:
List<SampleData> sampleList = new List<SampleData>() {
new SampleData() { Id = 1, Name = "Peyton" }
};
listBox1.DataSource = sampleList;
listBox1.DisplayMember = "Name";
Or you can have it directly using the items property.
listBox1.Items.Add(new SampleData() { Id = 1, Name = "Sample" });
listBox1.DisplayMember = "Name";