I'm making a program that catalogs the names of the people I add in a listbox and save all the content to a file when you close the program.
Each line of the file is for a person:
Tommy
Marco
James
Dylan
When the program starts, the file data is loaded and add the names to listbox.
All this works great, but now I'm having trouble making something else.
Each person on the list need a variable to indicate whether it has paid and I want to save this variable together with his name on the file.
For this, I have:
bool paid;
private void checkbox_Paid_CheckedChanged(object sender, EventArgs e)
{
paid = true;
}
I have only one checkbox, and it needs to differ from each person in the listbox, according to the selected in the event:
private void listDOF_SelectedIndexChanged(object sender, EventArgs e)
{
}
But I do not know how to write this bool in the file for each person, save to the file together with name and load it.
I've tried something like:
foreach(string purchasers in listDOF.Items)
{
arq.WriteLine(purchases, paid);
}
Obviously this do not worked, I do not know how to assign the bool for each one of the purchasers and write it in the file.
I'm using .NET 4.5 in a WFA.
Thanks all in advance, if I able to do this, I will give a big step toward the knowledge.
First of all I would store the persons in a list in the application otherwise you will only have one bool for all the persons in the application and everyone will be set as payed or not payed.
public class Person
{
public string Name { get; set; }
public bool Payed { get; set; }
}
public List<Person> Persons { get; set; }
As simple way is to save it in a SCV file. Semicolons between fields and new row per post
Tommy; true
Marco; true
Then save like this
foreach(var person in Persons)
{
arq.WrtieLine("{0};{1}", person.Name, person.Payed);
}
I believe that this is a good case to turn your text file into JSON.
For example:
[
{ name: "Tom", hasPaid: true },
{ name: "Matias", hasPaid: false } // Urgh!
]
And In C# you can build up this JSON using anonymous objects:
List<object> people = new List<object>();
people.Add(new { Name = "Tom", HasPaid = true });
Finally, you can serialize to JSON using JSON.NET:
File.WriteAllText(#"C:\myfile.json", JsonConvert.SerializeObject(people));
...or deserialize it:
List<object> people = JsonConvert.DeserializeObject<List<object>>(File.ReadAllText(#"C:\myfile.json"));
Update
Maybe you should use an concrete class rather than an anoymous object, because the later is inmutable and you're going to get in troubles if you need to data-bind the object list to the whole ListBox.
You can declare a simple class like this:
public class Person
{
public string Name { get; set; }
public bool HasPaid { get; set; }
}
...add persons this way:
List<Person> people = new List<Person>();
Person person = new Person();
person.Name = "Tom";
person.HasPaid = true;
people.Add(person);
File.WriteAllText(#"C:\myfile.json", JsonConvert.SerializeObject(people));
And when it comes to deserializing the whole JSON array:
List<Person> people = JsonConvert.DeserializeObject<List<Person>(File.ReadAllText(#"C:\myfile.json"));
Update 2
It seems like you don't know you can bind a list to Windows Forms controls. See for example the following MSDN article.
Instead of List<T> you can use BindingList<T>. Check this CodeProject guide.
This way, when you add an item to the whole BindingList<T> the ListBox control will be automatically populated. If you remove one, it will also dissapear from the UI.
Both Windows Forms and Windows Presentation Foundation are powerful and productive if you leverage data-binding (also in Web development, say KnockoutJS!).
Related
I have a dataGrid with two columns in it, and I want to add rows to them in my .cs file with dataGrid1.Items.Add().
I know it takes in an object, but how does it determine which value in the object to take? It feels messy to just create a generic class just to put new rows into the dataGrid, is there another way to do this?
So below I have a generic object, how do I make it so that .Add will add in the name and age into dataGrid1?
generic class:
namespace myApp
{
public class generic
{
private string name;
private int age;
public generic(string n, int a)
{
name = n;
age = a;
}
public string getName()
{
return name;
}
public int getAge()
{
return age;
}
}
}
I've tried dataGrid1.Items.Add(new Item("Ann", 21)); //show a row of empty cells. I just cant wrap my head around how this works
edit for more info:
in my .xaml
<DataGrid x:Name="dataGrid1" VerticalAlignment="Top" />
in my cs file:
DataGridTextColumn nameColumn = new DataGridTextColumn();
DataGridTextColumn ageColumn = new DataGridTextColumn();
nameColumn.Header = "name";
nameColumn.Binding = new Binding("name");
dataGrid1.Columns.Add(nameColumn);
ageColumn.Header = "age";
ageColumn.Binding = new Binding("age");
dataGrid1.Columns.Add(ageColumn);
Then I have a click function, that whenever clicked will generate a new name and age, then add it to dataGrid1
By default, the DataGrid will generate a column for each public property in the data item class (AutoGenerateColumns should be true; if not, make it so in the XAML), so you need to add public properties accordingly. You should be defining your columns in XAML and creating a main viewmodel with an ObservableCollection of this generic class, instead of adding them to Items by hand, but Rome wasn't built in a day.
This version of your class should work:
public class generic
{
public generic(string n, int a)
{
name = n;
age = a;
}
public string name { get; set; }
public int age { get; set; }
}
Your intuition about this being "messy" is natural for somebody relatively new to the field, but it's mistaken. What's "messy" is trying to store all your data in user interface controls. When you write code that way, everything rapidly turns into a nightmare. Everything you need to do involves writing multiple lines of semi-redundant code to get to your data items and do anything with them. That way of doing things is like storing everything you own in the trunk of your car, then running out naked in the street after a shower to get dressed or when you need a clean fork. And naturally, all your logic is copied and pasted from one event handler to the next, then slightly modified.
I used to call that "RAD Syndrome" back in the 90s when "Rapid Application Development" was the hot buzzword for any environment like VB or Delphi. WPF does not encourage you to write code that way, and that's actually for the best. Think of it this way: Structured programming seemed a bit arbitrary to me on my first encounter with it when I was a kid in the 80s, and object oriented programming seemed weirdly arbitrary later on. But after I got used to working with them, I found them tremendously useful. Same kind of deal with this MVVM stuff.
I hope you can help out a fellow programmer. Basically, I want the user input from the Rich Text Box (taskNameRTB) to be assigned to the taskName; string variable in my class taskStructure which is in form1 shown below:
public partial class Form1 : Form
{
public class taskStructure
{
public string taskName;
public string taskDescription;
public int Priority;
public string dateAndTime;
}
public List<taskStructure> TasksArray = new List<taskStructure>(); //Declared a list data structure
In my second form which is where the user enters everything related to the task, I want to send this information to the list after the 'Create Task' button has been clicked:
private void createTaskBtn_Click(object sender, EventArgs e)
{
Form1 welcomeForm = new Form1();
welcomeForm.TasksArray[0].taskName = taskNameRTB.Text;
welcomeForm.TasksArray[0].taskDescription = taskDescRTB.Text;
}
However, when I do this I get a ArgumentOutOfRangeException and I do not understand why. I have also tried these:
welcomeForm.TasksArray[0].Add(taskDescRTB.Text);
welcomeForm.TasksArray.Insert(0, taskNameRTB.Text);
welcomeForm.TasksArray.Add(taskDescRTB.Text);
taskNameRTB.Text = welcomeForm.TasksArray[0].taskName;
But the ones that run come up with the same error ArgumentOutOfRangeException and some of them don't work, such as:
welcomeForm.TasksArray[0].Add(taskDescRTB.Text);
I'm aware that the list has not been initialized, but how can I initialize it when it doesn't allow me to initialize it with user input...
Any light you can shed on this will be really helpful
Kind Regards,
Kieran
You need to add a new taskStructrue to the list.
welcomeForm.TasksArray.Add(new taskStructure
{
taskName = taskDescRTB.Text,
taskDescription = taskDescRTB.Text
});
But personally I'd rewrite that class to follow naming conventions and to use properties instead of public fields.
public class TaskStructure
{
public string TaskName { get; set; }
public string TaskDescription { get; set; }
public int Priority { get; set; }
public string DateAndTime { get; set; }
}
have you tried
welcomeForm.TasksArray.Add(new taskStructure(taskDescRTB.Text));
I don't know what taskStructure is, but you need to fill TasksArray with types of it.
Your TaskStructure is a class, and you are putting all TaskStructure objects into a list,
public List<taskStructure> TasksArray = new List<taskStructure>(); //Declared a list data structure
Does your Form1() have a constructor that calls InitializeComponents()?
If so, you could try adding TasksArray = new List<taskStructure>() right below InitializeComponents(), because it looks like you're trying to access the list data structure that hasn't been initialized with new.
Alternatively
As another user noted, you can create a constructor class for TaskStructure like this:
public TaskStructure(RTB rtb1, rtb2, rtb3) //where RTB is the rich text box type
{
taskName = rtb1.text;
taskDescription = rtb2.text;
//and so on.
}
Then you can do TaskArray.add(new TaskStruture(rtb1,rtb2,rtb3).
Thrid Edit
Just realized your TaskArray is actually a List, which in C# (and Java), you cannot access it with an index like TaskArray[0], you have to use getter and setter methods, which in this case is TaskArray.add(), and TaskArray.get(0), you're getting ArgumentOutOfRangeException because you're trying to access a List using square indexes like this --> [0]. You can actually access a list doing list1, as pointed out by another user.
Here's a good tutorial on C# lists, by DotNetPerls
Suppose I have a list of objects of a C# class. I wish to have a 2d array (or list of lists, or something else that can do the same) that can hold information of the relations between all objects in the list. The class could look like this:
public class SimplePoint
{
public string strName{ get; set; }
};
public class SimpleRoute
{
public int iDistance{ get; set; }
};
public class Place
{
public ObservableCollection<SimplePoint> points;
// Below array should dynamically increase/decrease size
// depending on length of list of points
// The array should store 2 values for each possible set of points:
// distance from x to y, and distance from y to x
public SimpleRoute[, ] routes;
};
The 2d array/table should have one row and one column for every element in the list. When an element is added to the list, the 2d array should grow in two directions, and when an element is deleted, the table/array should shrink in two directions.
The two dimensional array as declared in the above code will obviously not work for this. Rather, I am wondering if the 'SimpleRoute' class could somehow abserve the ObservableCollection 'points', and internally maintain the table of distance data.
Later I wish to also be able to store the data from the 2d array/table - or from the class behind/around it - in an XML (through serialization) and be able to load it again (through deserialization). The relation to the list of 'SimplePoints' should be maintained.
Lastly, the data (ie. the distances) in the automatically adjusting table should editable by the user. I will create the GUI using WPF.
I am wondering what is the best approach for this in C#/.NET, but find it hard to think of something elegant. Searching hasen't yielded a lot of results, though I may be looking in the wrong place.
Maybe there is some easy solution? I am relatively newto .NET programming.
I think that you're asking for information on quite a big domain of .net / general OOP practices, so it's really hard to provide a decent answer without a bit of context, but I'll try to give you some pointers.
I'm assuming you have two classes, say Group and Person, with the following simple definitions:
class Group
{
public string name { get; set; }
public List<Person> Persons = new List<Person>();
}
class Person
{
public string name { get; set; }
public int age { get; set; }
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
}
You have created an object Group with an 1:N relationship to the object Person.
You can test this method with the following test function:
public static void test()
{
Group group =new Group();
group.name= "Friends";
Person p = new Person("John",30);
Person p2 = new Person("Rute",25);
Person p3= new Person("Richard",17);
group.Persons.Add(p);
group.Persons.Add(p2);
group.Persons.Add(p3);
foreach(Person person in group.Persons)
{
Console.WriteLine("{0} is {1} years old. He is in group {2}.",person.name,person.age,group.name);
}
}
Is this what you intended? If you want to create a different type of relationship (N:N, N:1), I can modify my code to help you with that too.
I am having problems getting the items from my list into a textbox. I’m using Windows forms in Visual Studio.
I have one form with some textboxes and put the inputs to a list. The list contains customers and the user gives the customer an id from one of the textboxes. Now I want to get all the items from the list to the next form.
I have the list in a public class:
public class myClassCustomer
{
public List<customerInformation> cusInformation = new List<customerInformation>();
public class customerInformation
{
public string customerId { get; set; }
public string phoneNumber { get; set; }
public string adress { get; set; }
}
And the code for saving the inputs in form1:
myClassCustomer myClassCustomer = new myClassCustomer()
customers.cusInformation.Add(new myProject.myClassCustomer.customerInformation
{
customerId = txtCustomerId.Text,
phoneNumber = txtPhonenumber.Text,
adress = txtAdress.Text
});
Now in form2 this is what I have written so far:
public form2()
{
InitializeComponent();
myClassCustomer myClassCustomer = new myClassCustomer();
}
Does anyone know how to get all the items from the list?
I'm presuming that the question boils down to how to "get all of the items from the list to the next form", rather than the title suggests "get items from list by id".
The question "Anyone knows how to get all the items from the list?" is a bit tautological because the list already is all of the items.
So I am going to focus on answering your question about the list items being available to the next form. I presume that "Customers" is essentially just a List, and if it isn't, you should probably consider using that instead of a homebrew list class unless you have a very specific requirement otherwise. At the very least, I am hoping that the customers class implements the IEnumerable interface.
In order for this other form to be able to access your list of customers, you need to be making that information available somehow: for instance, you could change the other form's constructor to require a list of customers. Then, when this original form invokes the second form, it must pass in that list it has presumably populated as a parameter.
There are a few other ways this information could be propagated around your application but it sounds like you're just at a beginner level, so the method given above is probably the simplest.
Perhaps you could clarify your question if this does not answer it.
Edit: Some of your own edits have changed the code I was commenting on. It now appears that you're not after a list, but the advice is the same; instead of passing a List, you're just passing a myClassCustomer.
Just define a public property in your form1
public List<customerInformation> AllCustomers
{
get { return yourList; }
}
When opening your Form2 from Form1 use this code:
Form2 f2 = new Form2();
f2.Show(this);
Then you can access your customers from Form2:
var myCustomerList = ((Form1)Owner).AllCustomers;
I am trying to copy an object onto the windows clipboard and off again. My code is like this:
Copy on to clipboard:
Clipboard.Clear();
DataObject newObject = new DataObject(prompts);
newObject.SetData(myString);
Clipboard.SetDataObject(newObject);
Where prompts is a List<Data.Sources.PromptResult> collection.
Copy off clipboard:
IDataObject dataObject = System.Windows.Forms.Clipboard.GetDataObject();
if (dataObject.GetDataPresent(typeof(List<Data.Sources.PromptResult>)))
{
Type type = typeof(List<Data.Sources.PromptResult>);
Object obj = dataObject.GetData(type);
return (List<Data.Sources.PromptResult>)dataObject.GetData(type);
}
The GetFormats() shows the format as being in the list and the GetDataPresent(List<Data.Sources.PromptResult>) returns true but if I try to get the object out of the Clipboard class with GetData(List<Data.Sources.PromptResult>) I get a return of null.
Does anyone have any idea what might be wrong?
OK I tried to add list of my user type to clipboard and get it back...
Here is what I tried:
My User Class:
public class User
{
public int Age { get; set; }
public string Name { get; set; }
}
Rest of Code:
// Create User list and add some users
List<User> users = new List<User>();
users.Add(new User { age = 15, name = "Peter" });
users.Add(new User { age = 14, name = "John" });
// Lets say its my data format
string format = "MyUserList";
Clipboard.Clear();
// Set data to clipboard
Clipboard.SetData(format, users);
// Get data from clipboard
List<User> result = null;
if (Clipboard.ContainsData(format))
result = (List<User>)Clipboard.GetData(format);
...and result was null :)
...until I marked User class as Serializable
[Serializable]
public class User
{
//...
}
After that my code worked.
Ok its not the answer but maybe it helps you some how.
#Reniuz thanks for your help it has helped me to work out the answer.
In order to get the text and custom object data out of the Clipboard with multiple formats I have implemented the IDataObject interface in my own class. The code to set the data object must have the copy flag set like this:
Clipboard.Clear();
Clipboard.SetDataObject(myClassThatImplementsIDataObject, true);
To get the data out again the standard text can be retrieved using:
Clipboard.GetText();
The data can be retrieved using the data method:
Clipboard.GetData("name of my class");
The other point that was helpful was to test that the object I was putting into the clipboard could be serialized by using the BinaryFormatter class to perform this test... If an exception is thrown that copying to the clipboard would also fail, but silently.
So my class has:
[Serializable]
public class ClipboardPromptsHolder : IDataObject
{
...
}
I had a similar scenario and after marking my class as serializable I got it to work.
So try putting the Serializable attribute on your class Data.Sources.PromptResult.
I found out that, if your class is derived from a different class, the base class also needs to be made [Serializable], otherwise that recipe does not work. In my case, it was something like
public abstract class MyAbstractUser
{
...
}
[Serializable]
public class MyUser : MyAbstractUser
{
...
}
When I tried to exchange values of MyUser over the clipboard, it did not work, but when I added [Serializable] to MyAbstractUser, it did work.
I came across this while trying to send a list of items to my clipboard. What I needed was the string representation of those items, not the entire object. I tried a few of the suggestions here, to no avail. However, I did come up with my own solution and I wanted to share it. See below.
public static void CopyToClipboard<T>(this IEnumerable<T> items)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (T item in items)
stringBuilder.Append(item.ToString()).AppendLine();
Clipboard.SetText(stringBuilder.ToString());
}
Add this as an extension method and be sure to override your custom Type's ToString() method.