ListBox
L.S.,'
I've inserted a ListBox in my Form.
I want to fill this ListBox with certain class (List) Array "records" . (In Turbo-C called a structure)
From every "record" I want to display 5 items on the same line.
The idea is to select a record, modify it, and display it in the ListBox again.
I've checked a couple of C# books, but unfortunately I've not been able to find how to do this.
I would appreciate it if you can advise me on this subject.
(Maybe a ListBox is not the best option for what I want to achieve.)
Kind Regards,
Baily
Sam HobbsPosted Dec 19, 2009, 12:08 PM
BailyPosted Dec 19, 2009, 10:40 AM
Hi Sam,
You are absolutely right.
My apologies.
Regards,
Baily
Sam HobbsPosted Dec 18, 2009, 3:34 PM
I am not sure if you must use the data in the same format on disk as in Turbo-C or if you can convert the data. If you can convert the data then I strongly suggest that you do. You can use SQL Server Express for free and the your program can be used by other systems that have the full SQL Server. Another possibility is to store the data as XML. If you do that then the program does not need database software but XML is not as flexible and powerful as SQL Server.
If you must keep the same format on disk, then I am sure there are .Net equivalents of what you need. One possibility that you might not be aware of is memory-mapped files; doing that, you can access the data on disk as if it was in memory.
Here are a possible answer for some of your questions.
I am not sure what you mean by "set the width of the item field" but if you are asking about the DataGridView's column width then the DataGridView has many ways to set column widths. There are options for getting the widths set automatically.
I am not sure what you mean by "make sure that all numeric data is vertical in-line" but if I understand then that will be done automatically if you use a DataGridView.
As for data alignment within DataGridView columns, you can specify that too using the DataGridView.
As for using a Combo-box to allow selection of various options, if you have an option code in your data and you want to show a textual description for the user to select from but then store the code in the data, then you can do that too. Since I am not sure what you will use for saving the data, it is not clear how you would do that, but it is possible. The MSDN has samples of that kind of thing.
One thing you can look at is the Data Walkthroughs. You don't need to do those in any order; do the ones useful for you.
Sam HobbsPosted Dec 18, 2009, 12:42 PM
I think that in forums such as this it helps to limit each thread to one question. That makes the forums more useful for others and it makes it more likely that you will get help.
If someone is looking for answers to the later questions in this thread then they might miss getting what they need because the thread subject might not indicate the later subjects. If someone else can help you with the later subjects then they might not look at your thread since the subject indicates something different.
Also note that people helping you get credit for being helpful. If I have helped you, then it would help me if you checked the box indicationg that my answer helped you. The problem is that if you do that, then the Lizard won't get credit for helping you.
I am not sure what you are asking in the later questions. I will try to understand it but I think it would be best if you create a new thread or threads for your current questions.
One thing that might help is that you can use a DataView to show the details of the row selected in a DataGridView. I am not sure if that is relevant to what you are doing. If you do want to use a DataView then the easiest way to do that is to drag one from the data sources window and drop it onto the form. The trick is to change the node in the data sources window to details instead of grid. Alternatively you can just drag a DataView from the toolbox to the form and then set up the datasource and such "manually". I can provide details if you want to do taht; either here or in a new thread.
For the future, though, I think it is better to limit each thread to one question, keeping in mind that it helps others in the future who are looking for answers and it helps you to get answers to your current questions.
theLizardPosted Dec 17, 2009, 8:09 PM
I was not sure where the data was coming from, since it is a binary file and you know its structure you could use something like this
class Class1
{
int recLength = 15;
int recStart = 0;
int recEnd = 15;
public void readRecords(string file)
{
byte[] b = File.ReadAllBytes(file);
byte[] c = b.GetValue(recStart, recEnd);
recStart += recEnd;
recEnd += recLength;
File.WriteAllBytes(file, b);
}
I would fill the array with all records rather than trying to load record by record, it would be easier to manage.
Setting the width of a grid column can be done dynamically depending on the length of the field itself
column alignment can be set left, right center
Yes you can use a combo box to do what you want, and you can also have the combo box in tyhe grid cell relating to the field
DataGridViewComboBoxCell cel = new DataGridViewComboBoxCell();
DataGridViewComboBoxCell.ObjectCollection cboc = new DataGridViewComboBoxCell.ObjectCollection(cel);
cboc.Add("Commodity a");
cboc.Add("Commodity b");
cboc.Add("Commodity c");
cboc.Add("Commodity d");
I am not sure what you mean by e-mail private String Empty!!!
I have not really tried anything here but I am sure that you will get the idea's from my examples.
Let me know...
BailyPosted Dec 17, 2009, 6:57 PM
Hi theLizard,
Thanks for all your tips and suggestions, I really appreciate it.
Over the weekend I'll go through it and will reply early next week.
To answer your questions:
How I want to load data from db and how do you want to save the data?
public partial class Form1 : Form
{
List ItemRecN = new List();
public Form1()
{
//When selecting a menu-item "Load File" I want to load a binary file fill the array with these "data records".
The "Data records" have to be modified, if required.
New "Data records" have to be added etc.
At the end the complete array has to be saved as a new binary file.
I don't know if it's easier to load just record by record as I was used to do in Turbo-C as following:
d_filerw(int code)
{
FILE *fptr;
long int offset;
fptr=fopen(TEMPFILE,"r+b");
offset = (MAXREC-1) * sizeof(rec1);
fseek(fptr,offset,SEEK_SET);
if(code == 1)
fread(&rec1,sizeof(rec1),1,fptr);
else
fwrite(&rec1,sizeof(rec1),1,fptr);
offset = (MAXREC-2) * sizeof(rec2);
fseek(fptr,offset,SEEK_SET);
}
Kind Regards,
Baily
theLizardPosted Dec 16, 2009, 8:52 PM
public
As far as list box or data grid, well it really depends on how you want things to appear, a grid view would be my choice.
How do you want to load data from db!
How do you want to save the data!
A suggestion, as you already have a myRecord class, add a string variable call it say sqlStatement then have a getter, setter for it, make sure that you add this to properties that wll affect the construction of the sqlStatement string
[RefreshProperties(RefreshProperties.All)]
public char my_comm //just a note, I always sow properties with an UPPER case first Letter so my_comm can be referred to as Comm so that the privet an public members are named the same, easier to remember.
{
get { return comm.; }
set { comm = value;
buidDisplayString(); //or
buidSqlStatement();
}
}
private void buildSqlStatement()
{
string s = "INSERT INTO table(field,field,field,field,field,) Values( ...........";
//you can build the string based on the values from the other properties and use.
// or use this as a display string for a list box, the possibilities are endless..
}
just as an example here is a property of my Cryptography component, don't try to understand how it works just look at what can be done.
///
/// bool, true encrypts the string, false decrypts the string make sure u use the same
/// HashAlgorithm when decrypting.
///
[CategoryAttribute("Lizards"),DescriptionAttribute("bool, encrypt / decrypt a string given to CipherText"),]
public bool Encrypt
{
get { return (_encrypt); }
set {
if (value && !encrypted && !String.IsNullOrEmpty(CipherText))
{
if (CipherText.IndexOf(prefix) == -1)
CipherText = prefix + CipherText;
hashAlgorithm = (hash == 0 ? "SHA1" : "MD5");
CipherText = encrypt.Encrypt(CipherText,PassPhrase, SaltValue, hashAlgorithm, PasswordIterations, InitVector, (int)KeySize);
_encrypt = value;
encrypted = true;
}
else
{
if (Encrypted && CipherText.IndexOf(prefix) == -1)
{
hashAlgorithm = (hash == 0 ? "SHA1" : "MD5");
CipherText = encrypt.Decrypt(CipherText, PassPhrase, SaltValue, hashAlgorithm, PasswordIterations, InitVector, (int)KeySize);
_encrypt = value;
encrypted = false;
}
}
}
Your setter function can be as simple as you want it to be or as complex as you want it to be.
Hope this helps
BailyPosted Dec 16, 2009, 8:04 PM
Hi theLizard ,
Thanks again.
On both listing I received the following error:
rList.listItem is inaccessable due to its protection level.
class rList : List
{
private List
private myRecord m;
public List
{
get { return(listItem); }
set { listItem = value; }
}
Regards,
Baily
BailyPosted Dec 16, 2009, 7:58 PM
Hi theLizard,
Thanks for your get-set suggestions. Sofar everything is working.
Only received an error stating that ItemRec.descr is inaccessable due to its protection level.
Note: made all class members private members as mentioned.
Having read my description of the program, what do you advise me to use: a ListBox or a DataGridView?
Kind Regards,
Baily
theLizardPosted Dec 16, 2009, 4:17 AM
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public class myRecord
{
private int r;
private int x;
private int max = 9;
public int R
{
get { return (r); }
set {
if (value >= 7)
MessageBox.Show("More than 7!", "error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
r = value; }
}
public int X
{
get { return (x); }
set { x = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsApplication1
{
class rList : List
{
private List
private myRecord m;
public List
{
get { return (listItem); }
set { listItem = value; }
}
public myRecord AddRecord
{
get { return (m); }
set {
listItem.Add( value.X.ToString() + ", " + value.R.ToString());
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
myRecord m = new myRecord();
m.R = 22;
m.X = 9;
rList myR = new rList();
myR.AddRecord = m;
listBox1.Items.Add(myR.ListItem[0]);
}
theLizardPosted Dec 16, 2009, 4:13 AM
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public class myRecord
{
private int r;
private int x;
private int max = 9;
public int R
{
get { return (r); }
set {
if (value >= 7)
MessageBox.Show("More than 7!", "error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
r = value; }
}
public int X
{
get { return (x); }
set { x = value; }
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsApplication1
{
class rList : List
{
private List
private myRecord m;
public List
{
get { return (listItem); }
set { listItem = value; }
}
public myRecord AddRecord
{
get { return (m); }
set {
value.R = 2;
value.X = 1;
listItem.Add( value.X.ToString() + ", " + value.R.ToString());
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
myRecord m = new myRecord();
m.R = 22;
m.X = 9;
rList myR = new rList();
myR.Add(m);
myR.AddRecord = m;
listBox1.Items.Add(myR.ListItem[0]);
}
theLizardPosted Dec 16, 2009, 3:04 AM
My get set suggestion will work for you in any scenario,
Class ItemRec
{
public int item; //item number
public char comm; //Commodity code
public string descr; //Description
public double sounding; //Sounding or Ullage
public double volume; //Volume or number of items
public double price; //Price per item/M3
public double totalPrice; //Total price
private string lisValue . String.Empty;
//you could set these also as properties
public int my_item
{
get { return number; }
set { number = value;}
public char my_comm{
get { return comm.; }
set { comm = value;}
}
public string my_descr
{
get { return descr; }
set { descr = value;}
}
public double my_sounding
{
get { return sounding; }
set { sounding = value;}
}
public double my_volume
{
get { return volume; }
set {
//***********************************
if(value > maxVolum || value < minVolum)
{
MessageBox.Show( ..... );
return;
//you can do all sorts of things here, but do not call itself
}
volume = value;
listValue = item + ", " + comm +", " + desc +", ..." + value; //this is an example of what you can also do with the proper conversions.
}
}
public string ListValue
{
get{return(listValue);}
set{listValue = value;}
}
public double my_price
{
get { return price; }
set { price = value;}
}
public double my_totalPrice
{
get { totalPrice price; }
set { totalPrice = value;}
}}
try it out, you will see that it will work...
These are methods used in control development which I have created a few of...
And just to make it more interesting you could also create a class, call it myDbRecordList example;
namespace ...
public clase myDbRecordList : List
{
}
then in your form
itemRec ir = new itemRec();
ir.desc = "whatever'
myDbRecordList mdl = new myDbRecordList();
mdl.Add(ir);
then get items by
mdl[index].comm
my usual disclaimer is that there would need to be a bit more work done to this but you do want to learn!
BailyPosted Dec 15, 2009, 6:48 PM
Hi theLizard,
Thanks for your contribution on my problem.
To answer your question : The number of items per record are static.
The number of records is dynamic.
Kind Regards,
Baily
BailyPosted Dec 15, 2009, 6:44 PM
Hi Sam,
Thanks for your help sofar. I'll try to explain what I want to achieve and maybe you will have some ideas/suggestions on how to do this.
This program is part of a financial program. For a warehouse I want to be able to calculate the total value of their stock and at the same time provide a stock list.
The Stock consists of liquids (value per M3) and other items.
The number of items per "record" is for every commodity the same. The number of records
can vary. (Items will be added or removed from the stock)
Volumes of Liquids are measured by tank soundings and via a table the total volume will be calculated. Later with the total volume and the value per M3 the total value will be calculated.
Items per record are static.
Number of records is dynamic.
Depending on the commodity different items have to filled-in for every record.
Example (part of program):
Class ItemRec
{
public int item; //item number
public char comm; //Commodity code
public string descr; //Description
public double sounding; //Sounding or Ullage
public double volume; //Volume or number of items
public double price; //Price per item/M3
public double totalPrice; //Total price
public int my_item
{
get { return number; }
set { number = value;}
public char my_comm
{
get { return comm.; }
set { comm = value;}
}
public string my_descr
{
get { return descr; }
set { descr = value;}
}
public double my_sounding
{
get { return sounding; }
set { sounding = value;}
}
public double my_volume
{
get { return volume; }
set { volume = value;}
}
public double my_price
{
get { return price; }
set { price = value;}
}
public double my_totalPrice
{
get { totalPrice price; }
set { totalPrice = value;}
}}
In Class Program a new object will be made:
List ItemRecN = new List();
In Class Program Form1 will be opened:
Application.Run(new Form1()):
public partial class Form1 : Form
{
List ItemRecN = new List();
public Form1()
{
}
.
.
.
.
.
.
}
A menu is present in Form1.
MenuItem1 Opens a previous StockFile and add records to the ArrayList : ItemRecN
(Number of record for every file is not constant.)
MenuItem2 Opens a Form with a ListBox or DataGridView for all items per record for the
Liquid commodities.
Fill in sounding.
Instead of filling in the sounding it should also be possible to use the ullage.
ComboBox????
(If ullage will be used the program has to calculate the sounding)
Opens TankFile and with as input the sounding information and as output the
Volume.
Calculate total value for this commodity. (Volume * Price)
Price should be possible to be changed .
Possibility to add new commodity record and fill in the "description" field.
MenuItem3 Opens a Form with a ListBox or DataGridView for all other commodities.
Fill in number (use item Volume) of items.
Calculate total value of this commodity. (Volume * Price)
Price should be possible to be changed .
to add new commodity record and fill in "description""
I've written this program in Turbo-C before, but would like to re-write it in Visual C#.
I was thinking of using a special form for updating the record.
- Select a record within the ListBox or DataGridView.
- Copy these record items onto this special "mutation"form.
- Update the records.
- Replace the old record with the new record in the ListBox or DataGridView.
At the end these "records" must be written to a new StockFile.
Kind Regards,
Baily
Sam HobbsPosted Dec 15, 2009, 2:05 AM
If the answers provided by theLizard works for you then do things that way. I suspect however that those suggestions are inconsistent with your requirements.
If when you say "some items cannot be accessed" it is not clear whether you mean and entire column (all items of a specified field) or you mean some items of a column but not all items in the column. I think you need to protect some rows but not the data in other rows. If so then the solution is more complicated.
I am also not sure what you mean by "format the item fields"; do you need the formatting to have any affect on the data? What happens when a field that has more than the maximum number of characters is changed? How does that affect the data that is put back? Look at the CellFormatting event of the DataGridView. Note that it suggests setting the Format property of a cell (actually a column) and that might be all you need to do.
As for giving a warning if data is inconsistent with a specified criteria, I think there are validation events that can be used. You should look through all the events that the DataGridView offers. There are many; for validation, look at the CurrentCellDirtyStateChanged, CellValidating and CellBeginEdit events.
As for finding more information, it depends on what you need help with. For working with objects as data sources, it will help to learn more about the C# language and about the use of classes in C#.
theLizardPosted Dec 14, 2009, 10:28 PM
Q. Is it possible that some items cannot be accessed (prevented from changing)?
Yes, do not have set{item? = vale;}
Q. Can I format the item fields,i.e. max. number of characters, max. number of digits behind the comma etc?
Yes in the setter do some thing like this
set{if(value.leng > 5)
{value = value;
messagebox( ... )
return;}}
Q. Can I limit the input data, i.e. give a warning if a value is not within certain limits?
Yes the same as above check length and value range.
Q. Where can I find more information on these Tool items (Can you recommend a book)?
The best way is to do what you are doing, ask questions if you are genuine in wanting to learn then there a genuine people wanting to help you learn.
Now I have a question for you, are the number of items static or can they grow? if they can grow then Sam's approach while it works for a static number of items will no work for a dynamic number of items, you would need to do a bit more and Sam is correct in that there are other ways to achieve your objective.
BailyPosted Dec 14, 2009, 8:09 PM
Excellent Sam,
It's working. and how to continue....
Few questions: Is it possible that some items cannot be accessed (prevented from changing)?
Can I format the item fields,i.e. max. number of characters, max. number of digits behind the comma etc?
Can I limit the input data, i.e. give a warning if a value is not within certain limits?
Where can I find more information on these Tool items (Can you recommend a book)?
Thanks and Kind Regards,
Baily
Sam HobbsPosted Dec 14, 2009, 2:09 AM
I am sorry that I did not understand your question initially. I think I understand now. I think there is an easier and more powerful way to do what you seem to be doing. You can use a DataGridView control instead of a ListBox. It is a little more work to learn how to do, but once you know how, there are many other things that you can do to make things easier for yourself and the user.
You should start by creating a new C# Windows Forms project, then create a class for the record; something such as the following:
Note that I am using properties for the items and each property is public. I hope you understand how properties work.
Then build the project, just to ensure that the system can see the new class. Then go to the Data Sources window and click on Add a Data Source. In the options box, click on Object (not Database). In the next box, your project should be shown at the top of a tree. Expand your project's node and find the class that you just created and select it and then click the Next button then click Okay. After that, the Data Sources window should show a tree with the new data source with your record object and the fields as sub-nodes. Drag the record node to the new form in the project. You can build and test that, but the DataGridView will be empty of course.
Then add records as in the following:
You can do that in the Load event of the form. For you, the data will be read from the file.
Note that the data in the DataGridView can be edited in the DataGridView, so you don't need to do anything to make that work. You do however need to add a bit more code to save the edited data; I will explain that if you want it but first get the stuff I show above working for you.
Baimey RajeshPosted Dec 12, 2009, 1:34 PM