In my app, I have a few of checkListBoxes and I need to save clicks on this list. That means for the next time I don't need to click on them again and again.
Code:
public Form2()
{
InitializeComponent();
InitializeSecondForm();
}
private void InitializeSecondForm()
{
this.Height = Properties.Settings.Default.SecondFormHeight;
this.Width = Properties.Settings.Default.SecondFormWidth;
this.Location = Properties.Settings.Default.SecondFormLocation;
this.FormClosing += SecondFormClosingEventHandler;
this.StartPosition = FormStartPosition.Manual;
}
private void SecondFormClosingEventHandler(object sender, FormClosingEventArgs e)
{
Properties.Settings.Default.SecondFormHeight = this.Height;
Properties.Settings.Default.SecondFormWidth = this.Width;
Properties.Settings.Default.SecondFormLocation = this.Location;
Properties.Settings.Default.Save();
}
I tried to use this question for my answer, but it's not working: Save CheckedListBox Items to Settings
With a simple checkBox it's not a problem, but here we have a list.
Any idea how to do it?
Perhaps saving identifiers of each checked item to a json file.
In the following I did on CheckedListBox, for multiple CheckedListBox controls you need to adjust the code to use one json file with a modified structure to account for multiple CheckedListBox control or one json file per CheckedListBox.
Example, load items into the following class
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public override string ToString()
{
return ProductName;
}
}
Use the following class for read/write to a json file, in this case using json.net but will work also with system.text.json.
public class JsonOperations
{
/// <summary>
/// In your app you need to setup a different file name for each CheckedListBox
/// </summary>
public static string FileName =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Checked.json");
/// <summary>
/// Save only checked products
/// </summary>
/// <param name="list"></param>
public static void Save(List<ProductItem> list)
{
string json = JsonConvert.SerializeObject(list, Formatting.Indented);
File.WriteAllText(FileName, json);
}
/// <summary>
/// Read back if file exists
/// </summary>
/// <returns></returns>
public static List<ProductItem> Read()
{
List<ProductItem> list = new List<ProductItem>();
if (File.Exists(FileName))
{
list = JsonConvert.DeserializeObject<List<ProductItem>>(File.ReadAllText(FileName));
}
return list;
}
}
The following classes provide methods to get checked items set checked items from json mentioned above.
public static class CheckedListBoxExtensions
{
public static List<ProductItem> IndexList(this CheckedListBox sender)
{
return
(
from item in sender.Items.Cast<Product>()
.Select(
(data, index) =>
new ProductItem()
{
ProductID = data.ProductID,
Index = index
}
)
.Where((x) => sender.GetItemChecked(x.Index))
select item
).ToList();
}
public static void SetChecked(this CheckedListBox sender, int identifier, bool checkedState = true)
{
var result = sender.Items.Cast<Product>()
.Select((item, index) => new CheckItem
{
Product = item,
Index = index
})
.FirstOrDefault(#this => #this.Product.ProductID == identifier);
if (result != null)
{
sender.SetItemChecked(result.Index, checkedState);
}
}
}
public class CheckItem
{
public Product Product { get; set; }
public int Index { get; set; }
}
Form code would resemble the following to read checked items on form shown event and save checked item on form closing event.
public partial class SaveItemsForm : Form
{
private List<Product> _products = new List<Product>();
public SaveItemsForm()
{
InitializeComponent();
Shown += OnShown;
Closing += OnClosing;
}
private void OnClosing(object sender, CancelEventArgs e)
{
List<ProductItem> checkedItems = ProductCheckedListBox.IndexList();
if (checkedItems.Count > 0)
{
JsonOperations.Save(checkedItems);
}
else
{
JsonOperations.Save(new List<ProductItem>());
}
}
private void OnShown(object sender, EventArgs e)
{
_products = SqlServerOperations.ProductsByCategoryIdentifier(1);
ProductCheckedListBox.DataSource = _products;
/*
* Search for each product by id, if in the CheckedListBox check it
*/
var items = JsonOperations.Read();
if (items.Count >0 )
{
items.ForEach( x => ProductCheckedListBox.SetChecked(x.ProductID));
}
}
}
In such conditions, I prefer to have a simple database like SQLite.
Use this database to save the user profile. user profile data will store all such data. for example, the user and password can be saved into that to remember to the user for next time login, or all settings and configurations that user selected it during using the system.
Related
I have this code in my MainWindow.
The user enters Name, Phone and Email in the fields provided, selects Location and then the Name appears in the listbox, lstClients.
I'm trying to write a method to remove a selected name from the listbox.
namespace WpfApp_Employment_Help
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// client list
List<Client> ClientList = new List<Client>();
public MainWindow()
{
InitializeComponent();
}
// method to select location via radio button
public string GetSelectedLocation()
{
string selected = string.Empty;
if (RBLocE.IsChecked == true) { selected = "Edinburgh"; }
else if (RBLocG.IsChecked == true) { selected = "Glasgow"; }
else if (RBLocO.IsChecked == true) { selected = "Other"; }
return selected;
}
// method to create a new client on click
private void newClient(object sender, RoutedEventArgs e)
{
Client c = new Client(boxClientName.Text, boxClientPhone.Text, boxClientEmail.Text, GetSelectedLocation());
boxClientName.Clear();
boxClientPhone.Clear();
boxClientEmail.Clear();
ClientList.Add(c);
lstClients.ItemsSource = null;
lstClients.ItemsSource = ClientList;
}
// method to id selected client
private void AssignID(object sender, RoutedEventArgs e)
{
Client c = lstClients.SelectedItem as Client;
if (c != null)
{
c.AssignID();
}
lstClients.ItemsSource = null;
lstClients.ItemsSource = ClientList;
}
// method to remove selected client
private void RemoveClient(object sender, RoutedEventArgs e)
{
lstClients.Items.Remove(lstClients.SelectedItem);
}
}
}
When I run this code, I get Unhandled Exception:
System.InvalidOperationException: 'Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.'
how can I rewrite my RemoveClient method?
my code for the Client class is this:
public partial class Client
{
public string Name { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Location { get; }
public bool IDed { get; private set; }
public Client(string n, string p, string e, string l)
{
Name = n;
Phone = p;
Email = e;
Location = l;
}
}
I have Visual Studio 2022 which has been recently updated.
I have also tried the following solution but it gives me another unhandled error?
It looks like I need to change List </string/> and string to something else. but what?
private void RemoveClient(object sender, EventArgs e)
{
if (lstClients.Items.Count >= 1)
{
if (lstClients.SelectedValue != null)
{
var items = (List<string>)lstClients.ItemsSource;
var item = (string)lstClients.SelectedValue;
lstClients.ItemsSource = null;
lstClients.Items.Clear();
items.Remove(item);
lstClients.ItemsSource = items;
}
}
else
{
System.Windows.Forms.MessageBox.Show("No ITEMS Found");
}
}
System.InvalidCastException: 'Unable to cast object of type 'System.Collections.Generic.List`1[WpfApp_Employment_Help.Client]' to type 'System.Collections.Generic.List`1[System.String]'.'
As the error message suggests, you can't modify the ItemsControl via the collection view returned from the ItemsControl.Items property.
WPF is generally designed to work on the data sources instead of handling the data related controls (data presentation). This way data and data presentation (GUI) are cleanly separated and code will become a lot simpler to write.
In case of the ListView (or ItemsControl in general), simply modify the source collection.
To improve performance, the source collection should be a INotifyCollectionChanged implementation, for example ObservableCollection<T>, especially when you expect to modify the source collection.
This makes invalidating the ItemsSource e.g. by assigning null, just to set it again redundant and significantly improves the performance.
public partial class MainWindow : Window
{
// client list
public ObservableCollection<Client> ClientList { get; } = new ObservableCollection<Client>();
// method to create a new client on click
private void newClient(object sender, RoutedEventArgs e)
{
Client c = new Client(boxClientName.Text, boxClientPhone.Text, boxClientEmail.Text, GetSelectedLocation());
boxClientName.Clear();
boxClientPhone.Clear();
boxClientEmail.Clear();
ClientList.Add(c);
// The following lines are no longer needed
// as the GUI is now notified about the collection changes (by the INotifyCollectionChanged collection)
//lstClients.ItemsSource = null;
//lstClients.ItemsSource = ClientList;
}
// method to id selected client
private void AssignID(object sender, RoutedEventArgs e)
{
Client c = lstClients.SelectedItem as Client;
// Same as the if-statement below
c?.AssignID();
//if (c != null)
//{
// c.AssignID();
//}
// The following lines are no longer needed
// as the GUI is now notified about the collection changes (by the INotifyCollectionChanged collection)
//lstClients.ItemsSource = null;
//lstClients.ItemsSource = ClientList;
}
// method to remove selected client
private void RemoveClient(object sender, RoutedEventArgs e)
{
var clientToRemove = lstClients.SelectedItem as Client;
this.ClientList.Remove(clientToRemove);
}
}
If you change the type of ClientList from List<Client> to ObservableCollection<Client>, you could simply remove the item directly from the source collection:
public partial class MainWindow : Window
{
ObservableCollection<Client> ClientList = new ObservableCollection<Client>();
public MainWindow()
{
InitializeComponent();
}
...
private void RemoveClient(object sender, RoutedEventArgs e)
{
ClientList.Remove(lstClients.SelectedItem as Client);
}
}
So I have a DataGridView called MyMovieDataDrid which is connected to a sql server, and I already have my IsDeleted property, and a delete repository which is shown below, by the way my IsDeleted property automatically shows up as a checkbox so if the checkbox is checked it's true if not it's false
public bool DeleteMovie(Guid id)
{
bool isDeleted = false;
var movie = _context.Movie.FirstOrDefault(m => m.Id == id);
if (movie != null)
{
movie.IsDeleted = true;
_context.SaveChanges();
isDeleted = true;
}
return isDeleted;
}
and here is my Delete button method so when I press it, it runs my logic and soft deletes a row from the DataGridView I've tried multiple solutions like using the selected row event handler to get the selected rows then running the repository method but none have worked so far.
private void DeleteButton_Click(object sender, EventArgs e)
{
Movie movie = new Movie();
if(MyMovieDataGrid.SelectedRow.Count > 0)
{
_movieRepo.DeleteMovie(movie.Id);
}
}
and my all of my properties
Movie movie = new Movie()
{
Id = Guid.NewGuid(),
IsDeleted = false,
MovieNames = MovieNameBox.Text;
}
and my AddMovie repostitory
public void AddMovie(Movie movie)
{
_context.Movie.Add(movie);
_context.SaveChanges();
}
Movie Repository Method
private NRIDataContext _context;
public MovieRepository()
{
_context = new NRIDataContext();
}
//GetMovie repository
GetMovie()
{
var movies = _context.Movie.Where(m => m.IsDeleted
==false).ToList();
return movie;
}
MyMovieDataGrid.DataSource = _movieRepo.GetMovie().OrderByDescending(x => x.MovieNames.First) .ToList();
so my question is how do I make my Datagrid know when to run my repository method and I feel like I have to somehow make write some code to where if the IsDeleted property is true it selects the whole row then I run my DeleteMovie Method but no solutions have worked.
I like Karen's approach for being more "how it should be done", but it's quite a far cry from what you've written and I suspect you might not want to change your current code massively
The basic problem with your approach is you don't get the movie id from the row that was clicked, you make a new movie which has a new random Guid which is supposedly guaranteed to not be in the database at all because Guids are very unlikely to repeat, and then you try and delete that:
private void DeleteButton_Click(object sender, EventArgs e)
{
//make a new movie with random id
Movie movie = new Movie();
if(MyMovieDataGrid)
{
//delete the new random id
_movieRepo.DeleteMovie(movie.Id);
}
}
this means that the odds of the movie you want deleting actually getting deleted are a staggering 5316911983139663491615228241121400000 to one; it probably won't happen if you start clicking now and keep going until the earth is engulfed by the sun going red giant 😀
Retrieve the Guid you want to delete from the row clicked on; add a CellContentClicked handler and check it's the deleted button column being clicked and then pull the movie id out of the row's data bound item:
private void DGV_CellContentClick(object sender,
DataGridViewCellEventArgs e)
{
//don't process clicks on the header row
if(e.RowIndex < 0) return;
//don't process clicks on columns other than delete
if(e.ColumnIndex != MyMovieDataGrid.Columns["nameOfYourDeleteColumn"].ColumnIndex) return;
//pull the movie from that row
Movie movie = MyMovieDataGrid.Rows[e.RowIndex].DataBoundItem as Movie;
if(MyMovieDataGrid) //I don't know what this means; a DataGridView is not a boolean
{
//delete the movie id
_movieRepo.DeleteMovie(movie.Id);
}
}
Consider setting up a filter in OnModelCreating in this case I'm using a model named Contact1 since I have this already. In the underlying table add the IsDeleted column but not in the model.
Below shows the basics to soft delete a row and remove it from the DataGridView. No proper repository.
public partial class Contact1 : INotifyPropertyChanged
{
private int _contactId;
private string _firstName;
private string _lastName;
public int ContactId
{
get => _contactId;
set
{
_contactId = value;
OnPropertyChanged();
}
}
public string FirstName
{
get => _firstName;
set
{
_firstName = value;
OnPropertyChanged();
}
}
public string LastName
{
get => _lastName;
set
{
_lastName = value;
OnPropertyChanged();
}
}
public Contact1()
{
}
public override string ToString() => $"{FirstName} {LastName}";
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
OnModelCreating
modelBuilder.Entity<Contact1>()
.HasQueryFilter(contact =>
EF.Property<bool>(contact, "isDeleted") == false);
Then override SaveChanges in the DbContext
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new ())
{
DoShadowyStuff();
return base.SaveChangesAsync(cancellationToken);
}
public override int SaveChanges()
{
DoShadowyStuff();
return base.SaveChanges();
}
Then in DoShadowlyStuff if the state is Deleted set the state to modified.
private void DoShadowyStuff()
{
ChangeTracker.DetectChanges();
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Deleted)
{
// Change state to modified and set delete flag
entry.State = EntityState.Modified;
entry.Property("isDeleted").CurrentValue = true;
}
}
}
Very basic read and delete operations
public class Operations
{
public static void Remove(Contact1 contact1)
{
using (var context = new ShadowContext())
{
context.Add(contact1).State = EntityState.Deleted;
context.SaveChanges();
}
}
public static List<Contact1> Contacts()
{
using (var context = new ShadowContext())
{
return context.Contacts1.ToList();
}
}
}
Basic form operations. Click the delete button, set the state of the current row to deleted, save changes which marks the contact as modified and sets the isDeleted. Next remove the remove from the BindingList which in turn removes the row from the DataGridView.
public partial class Form1 : Form
{
private BindingList<Contact1> _bindingList;
private readonly BindingSource _bindingSource = new ();
public Form1()
{
InitializeComponent();
Shown += OnShown;
}
private void OnShown(object sender, EventArgs e)
{
_bindingList = new BindingList<Contact1>(Operations.Contacts());
_bindingSource.DataSource = _bindingList;
dataGridView1.DataSource = _bindingSource;
}
private void DeleteButton_Click(object sender, EventArgs e)
{
Operations.Remove(_bindingList[_bindingSource.Position]);
_bindingList.RemoveAt(_bindingSource.Position);
}
}
This is a problem I am having in C# Visual studio 2019, and it should be relatively simple for somebody more experienced to help me, and I appreciate all help. I'm going crazy trying to figure this out! I have two listboxes, one called boyBox and one called GirlBox. I used to populate the listboxes with the text files:
private void populateBoys()
{
//Try to access the file, if problems arise an error message will show
try
{
//Declare object to access file
StreamReader inputFile;
inputFile = File.OpenText("..\\..\\BoyNames.txt");
//Loop to run through all items in the text file
while (!inputFile.EndOfStream)
{
//read lines from the file and add to the listbox
boyBox.Items.Add(inputFile.ReadLine());
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void populateGirls()
{
//Try to access the file, if problems arise an error message will show
try
{
//Declare object to access file
StreamReader inputFile;
inputFile = File.OpenText("..\\..\\GirlNames.txt");
//Loop to run through all items in the text file
while (!inputFile.EndOfStream)
{
//read lines from the file and add to the listbox
girlBox.Items.Add(inputFile.ReadLine());
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
To populate the listboxes with a list of popular boy and girl names called BoyNames.txt and GirlNames.txt. This seems simple enough, but I am being driven insane trying to find something that works for me to simply type a name into a textbox and have the program tell me if the name was in the list or not. The closest I got was :
private void boyButton_Click(object sender, EventArgs e)
{
string boyname = boyBox2.Text;
bool found = false;
for(int n = 0; n < boyBox.Items.Count; n++)
{
if (boyBox.Items[n] == boyname)
{
found = true;
break;
}
}
if (found)
MessageBox.Show("popular");
else
MessageBox.Show("not popular");
}
But it just says "Not Popular" even if I typed one of the names that IS in the list into the textbox "boyBox2". The listbox is "boyBox". I'm just trying to find help to figure out what code I can use to get it to work for letting me know if what I type into the textbox "boyBox2" is a name that is in the listbox/file or not. Thank you!
The following reads a file with girl names into a BindingList<GirlName>
which becomes the data source of a BindingSource which is set to a ListBox.
In a TextBox TextChanged event a lambda statement does a like/starts-with on names in the ListBox. If the TextBox is empty the filter is removed.
Containers for names
public class NameBase
{
public int Index { get; set; }
public string DisplayText { get; set; }
public override string ToString() => DisplayText;
}
public class GirlName : NameBase { }
public class BoyName : NameBase { }
Classes for taking a raw text file with girl names to a sorted list of girl names in a new file.
public static class Extensions
{
public static string ToTitleCase(this string sender)
=> string.IsNullOrWhiteSpace(sender) ?
sender :
CultureInfo.InvariantCulture.TextInfo.ToTitleCase(sender.ToLower());
}
public class FileOperations
{
public static string _fileName => "gNames.txt";
public static bool GirlFileExits => File.Exists(_fileName);
/// <summary>
/// Used to create a list of names without extra data
/// along with proper casing names
/// </summary>
public static void CreateGirlFile()
{
List<string> list = new List<string>();
/*
* girlnames.txt came from
* https://github.com/SocialHarvest/harvester/blob/master/data/census-female-names.csv
* populated via raw button, copied to girlnames.txt, set copy to output directory if newer
*/
var names = File.ReadAllLines(_fileName);
/*
* assumes comma delimited with at least one item
*/
foreach (var name in names)
{
string[] lineSplit = name.Split(',');
list.Add(lineSplit[0].ToTitleCase());
}
list = list.OrderBy(item => item).ToList();
File.WriteAllLines(_fileName, list.ToArray());
}
public static List<GirlName> ReadGirlNames()
{
List<GirlName> names = new List<GirlName>();
var lines = File.ReadAllLines(_fileName);
for (int index = 0; index < lines.Length -1; index++)
{
names.Add(new GirlName() {Index = index, DisplayText = lines[index]});
}
return names;
}
}
Form has a ListBox and TextBox which does a starts-with, could also be a contains or ends-with.
public partial class Form1 : Form
{
private readonly BindingSource _girlNamesBindingSource = new BindingSource();
private BindingList<GirlName> _girlsNamesBindingList;
public Form1()
{
InitializeComponent();
Shown += OnShown;
SearchTextBox.TextChanged += SearchTextBoxOnTextChanged;
}
private void SearchTextBoxOnTextChanged(object sender, EventArgs e)
{
if (_girlNamesBindingSource == null) return;
List<GirlName> filtered = _girlsNamesBindingList.Where(nameItem =>
nameItem.DisplayText.StartsWith(
SearchTextBox.Text, StringComparison.OrdinalIgnoreCase)).ToList();
_girlNamesBindingSource.DataSource = filtered;
}
private void OnShown(object sender, EventArgs e)
{
if (!FileOperations.GirlFileExits)
{
FileOperations.CreateGirlFile();
}
_girlsNamesBindingList = new BindingList<GirlName>(FileOperations.ReadGirlNames());
_girlNamesBindingSource.DataSource = _girlsNamesBindingList;
GirlsNameListBox.DataSource = _girlNamesBindingSource;
}
}
Simply because you try to compare BETWEEN Item and string value and, you must compare BETWEEN the Item's value and the string value so, the code must be like so
private void boyButton_Click(object sender, EventArgs e)
{
string boyname = boyBox2.Text;
bool found = false;
for(int n = 0; n < boyBox.Items.Count; n++)
{
if (boyBox.Items[n].Value == boyname)
{
found = true;
break;
}
}
if (found)
MessageBox.Show("popular");
else
MessageBox.Show("not popular");
}
OR
You must convert the Item to string using ToString() method so, the code must be like so
private void boyButton_Click(object sender, EventArgs e)
{
string boyname = boyBox2.Text;
bool found = false;
for(int n = 0; n < boyBox.Items.Count; n++)
{
if (boyBox.Items[n].ToString() == boyname)
{
found = true;
break;
}
}
if (found)
MessageBox.Show("popular");
else
MessageBox.Show("not popular");
}
You can see this question also
I am doing a school project in creating a POS system and i need to pass in through the same order list throughout the different form.The problem is everytime i return to the main menu, the list refreshes although i still need the data is there anyway to prevent this from happening?
public partial class Main : Form
{
List<string> order = new List<string>();
public Main()
{
InitializeComponent();
}
public Main(List<string> order)
{
InitializeComponent();
this.order = order;
}
this is the start code for the main menu
And this is the code to add the items from thelistbox to the list
private void confirmbtn_Click(object sender, EventArgs e)
{
order.AddRange(temp_order);
if (pendinglist.Items.Count != 0)
{
MessageBox.Show("Your Items have been added! yay!", "That Sushi", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("No items was selected.", "That Sushi", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
pendinglist.Items.Clear();
}
Thank you in advance for your help.Please let me know if anything else is wrong with the code too. again thank you for the help
You are probably closing the form and re-creating it every time you open it again, and since these orders are inside it, obviously the previous content is lost.
Solution : that list of orders should be outside main form
Here's a really simple pattern for you, it's really primitive but it works and should be enough/plausible for your homework : a static class
public static class MyModel
{
public static Order Order { get; set; }
public static void NewOrder()
{
Order = new Order();
}
}
public class Order
{
public Order()
{
Products = new List<Product>();
}
public List<Product> Products { get; set; }
public void AddProduct(Product product)
{
Products.Add(product);
}
}
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
And here's how you'd use it from a form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonNewOrder_Click(object sender, EventArgs e)
{
MyModel.NewOrder();
}
private void buttonAddProduct_Click(object sender, EventArgs e)
{
var product = new Product();
product.Name = "PS4";
product.Price = 1000000000.0m;
MyModel.Order.AddProduct(product);
}
private void buttonShowProductsInOrder_Click(object sender, EventArgs e)
{
var order = MyModel.Order;
var products = order.Products;
var builder = new StringBuilder();
foreach (var product in products)
{
var format = string.Format("Name: {0}, Price: {1}", product.Name, product.Price);
builder.AppendLine(format);
}
MessageBox.Show(builder.ToString());
}
}
Order will not vanish and will be accessible from many forms.
Obviously it's a pretty bad practice, gurus would use MVP (model view presenter), MVC (model view controller) or whatever pattern along a database behind, but there's little point to roll out such design for your question. You can/should take a look at what these concepts are, however.
Good luck !
I have two listBoxes. The first listbox contains the list of traffic violations. When you click the add button and execute the code, the listbox2 got this item "ListBoxTest.Violation", not the item being displayed from the listBox1...
What is wrong with my code?
namespace ListBoxTest
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
private List<Violation> violationList = new List<Violation>();
public MainForm()
{
InitializeComponent();
}
void MainFormLoad(object sender, EventArgs e)
{
LoadViolations(); // Initialize and add violations to violationList.
listBox1.DataSource = violationList; // Set the DataSource property.
listBox1.ValueMember = "Code";
listBox1.DisplayMember = "Description";
}
void LoadViolations()
{
Violation violation;
violation = new Violation("001", "Beating the red light");
violationList.Add(violation);
violation = new Violation("002", "Exceeding posted speed limit on the road");
violationList.Add(violation);
violation = new Violation("003", "Driving a vehicle without license to drive");
violationList.Add(violation);
violation = new Violation("004", "Driving a non registered vehicle");
violationList.Add(violation);
violation = new Violation("005", "Vehicle has no plate number");
violationList.Add(violation);
}
void BtnAddClick(object sender, EventArgs e)
{
listBox2.Items.Add(listBox1.SelectedItem); // Add item from listBox1 to listBox2;
}
}
/// <summary>
/// Violation Class
/// Properties: Code, Description
/// </summary>
public class Violation
{
private string _code;
private string _description;
public Violation(string code, string description)
{
_code = code;
_description = description;
}
public String Code
{
get { return _code; }
set { _code = value; }
}
public String Description
{
get { return _description; }
set { _description = value; }
}
}
}
Type cast the selected item to Violation. This should fix the problem.
Edit: I have modified the code to fix the issue.
private void AddClick(object sender, EventArgs e)
{
// Set the DataSource property.
listBox2.ValueMember = "Code";
listBox2.DisplayMember = "Description";
listBox2.Items.Add((Violation)listBox1.SelectedItem);
}
Make sure listbox2 has the same settings as listbox1, e.g. listbox2.ValueMember, listbox2.DisplayMember..