Saving data to database using linq - c#

I face problems with my codes about saving data into database. I have a Text box and a Combo box but when I key in data in the Text box and select data in the Combo box and click save, nothing happens and no error were found during compiling. Can I know what actually went wrong and give me some solution to it?
enter code here private void btnCreate_Click(object sender, EventArgs e)
{
using (testEntities Setupctx = new testEntities())
{
string selectST = cbSeats.SelectedItem.ToString();
string inputST = txtStation.Text;
var createStation = (from createST in Setupctx.stations
where createST.Seats == selectST
where createST.Station1 == inputST
select createST).SingleOrDefault();
if (createStation != null)
{
Setupctx.stations.AddObject(createStation);
Setupctx.SaveChanges();
txtStation.Text = "";
MessageBox.Show("New Station Has Been Created.");
}
}
}
Your help will be greatly appreciated.

I'm agreeing with #JamesD on making sure the event handler is called.
Additionally, when you get an object from a linq query and make changes to it, you need to save those changes it by calling SubmitChanges() on the DataContext. (I'm assuming that Setupctx is a DataContext object).
Read here for information on SubmitChanges()
Also, I don't know if you are using SQL or not. If so, here is a great tutorial: Linq to SQL Tutorial

You need to create a new station object like this:
if (createStation != null)
{
var obj = new Staion();
obj.Seats=selectST;
obj.Staion1=inputST;
Setupctx.Staions.Add(obj);
Setupctx.SubmitChanges();
txtStation.Text = "";
MessageBox.Show("New Station Has Been Created.");
}
More on LINQ To SQL here

This is the right way of doing it.
private void btnCreate_Click(object sender, EventArgs e)
{
using (testEntities Setupctx = new testEntities())
{
string[] stations = StationNameList();
station creStation = new station();
creStation.Station1 = txtStation.Text;
creStation.Seats = cbSeats.SelectedItem.ToString();
if (stations.Contains(txtStation.Text))
{
MessageBox.Show("This Station is already been created. Please enter a new Station.");
}
else
{
Setupctx.stations.AddObject(creStation);
Setupctx.SaveChanges();
txtStation.Text = "";
cbSeats.SelectedIndex = -1;
MessageBox.Show("New Station Has Been Created.");
}
}
}

Just to check off the list:
Have you made sure the button event handler is hooked up?
When you say
nothing happens
Do you mean the event handler is not called? You're not actually doing anything with the station you've retrieved from the database either. You're adding it back in to the stations list that you've pulled it out from.

Related

Keep DbContext open for DataGridView

I have a DataGridView and the DataGridView's DataSource is a BindingList I got from the Entity Framework (V6) via context.Person.Local.ToBindingList().
After I set the DataSource to this BindingList, I dispose the context, because I read that keeping the context open would be bad practice.
So, if I wanted to add a new row, I would click on the "add" button that comes with the BindingNavigator that got created when I dragged the "people" object data source to my Windows Form.
Every time I click the "add" button, I get an exception that tells me that the context has been disposed.
Do I need to keep the context open all the time when using DataGridView? Oh and: the DataSource might change during runtime depending on the selection of a ListBox Item.
Also, when the context has been disposed and I edited one row from the DataGridView, how could I find out (after multiple changes) which row has changed?
I tried to do:
foreach(DataGridViewRow row in peopleDataGridView.Rows)
{
People item = (People)row.DataBoundItem;
if (item != null)
{
db.People.Attach(item);
}
}
db.SaveChanges();
...but SaveChanges() did not recognize any changes. However, if I force every attached item to a "modified" state, it works. But I do not want to change 100 items to "modified", if only one got actually modified.
Any ideas?
EDIT 1
Oh well, so I changed my code to keep the context open all the time (or at least as long as the form gets displayed).
Now, I ran into a different problem (people may have many jobs):
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
//jobBindingSource.Clear(); this caused another error at runtime...
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
The DataGridView that is bound to this jobBindingSource instance shows the correct jobs for a person, but in addition to the jobs from the previously selected person. I tried to Clear() the entries, but if I do this and click on the same person twice, the datagridview starts to sometimes show no entries at all. A strange behaviour.
What am I doing wrong now?
EDIT 2
Okay... I found a solution myself. But I refuse to accept that this is the correct way to do it:
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
db.Dispose();
db = new PeopleJobsEntities();
db.People.Attach(p);
db.Entry(p).Collection(person => person.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
Only if I dispose the context and open it anew, the whole thing works. The reason is that if I clear the local cache (of db.Job.Local), its entries will not be reloaded again even if I use the Load() method. Is there some way to force the reloading of entities?
While I try not to keep the DBContext open for a long period of time, with datagrids you don't have much choice. I set my grid's DataSource property to IQueryable<T> and then all the edits, deletes and additions are taken care of by the grid and context itself. You just have to call dbContext.SubmitChanges() whenever you want to persist the changes. You can save each time a user leaves a row by saving on the RowLeave or the RowValidated event. Or you can save when you close the form. But also make sure you call dbContext.Dispose() when you close the form as well.
To find out which rows change you can view the ChangeSet that is returned by doing the following:
var changes = dbContext.GetChangeSet();
dbContext.SubmitChanges();
Be sure if your item is not null.
Check your connection string.
And, try this :
db.People.Add(item);
Instead of :
db.People.Attach(item);
Ok, thanks to #jaredbaszler I came up with this solution that works fine for me.
I decided to keep the DbContext alive all the time. To clear the local cache, I detached every entity inside in a loop. I think this is a very disgusting way to do it. There must be a better way...
This is what I have:
PeopleJobsEntities db;
public FormTest()
{
InitializeComponent();
db = new PeopleJobsEntities();
db.Database.Log = Console.Write;
db.People.Load();
List<People> peoplelist = db.People.Local.ToList();
listBox1.DataSource = peoplelist;
}
private void FormTest_FormClosing(object sender, FormClosingEventArgs e)
{
if (db != null)
db.Dispose();
}
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
People p = (People)listBox1.SelectedItem;
if(p != null)
{
List<Job> oldlist = db.Job.Local.ToList();
foreach (Job j in oldlist)
{
db.Entry(j).State = EntityState.Detached;
}
db.Entry(p).Collection(b => b.Job).Load();
jobBindingSource.DataSource = db.Job.Local.ToBindingList();
}
}
private void jobBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
foreach(DataGridViewRow row in jobDataGridView.Rows)
{
if(row != null && row.DataBoundItem != null)
{
Job j = (Job)row.DataBoundItem;
if(db.Entry(j).State == EntityState.Added)
{
if(j.People.Count == 0)
{
People people = (People)listBox1.SelectedItem;
if (people != null)
j.People.Add(people);
}
}
}
}
db.SaveChanges();
}
Editing entries works
Adding new entries works
Deleting entries works

My Music Player showing multiple instances of the same form, for each track

I am trying to create a simple media player that just runs from the notifyIcon tray using a context menu strip, sitting on an hidden form.
When I click on the menu item 'play mp3's' it opens up a folder, allowing me to select a bunch of mp3 tracks. These tracks are stored in a listbox on the hidden form allowing me to manipulate them through the C# code. The code I have will always play the first song, no problem, but the ones after that has been a pain.
The way I found to make the songs continue to play was by using ShowDialog for each song, but as you guessed that means there are multiple instances of the same form. Soon as I stop using the show.dialog, I am back to one song again. Is it because I am using the WMPLib without the actual player on the form, I am sure that is not the case. I have managed to pick up tons of knowledge on here to get me this far, like using PlayStateChange, being able to select the next Item in the list box and how to play a song list. Unfortunately most of the time this is with using the media player console and buttons.
Here is the specific code that is causing the issue, as it stands it plays every track, soon as I comment out showdialog, it only plays the first song.
private void trackplayer()
{
listBox1.SelectedIndex = listBox1.SelectedIndex + 1;
var selectedUrl = listBox1.SelectedItem.ToString();
player.URL = selectedUrl;
player.controls.play();
mytempFormOpen();
}
public void mytempFormOpen()
{
var myform1 = new Form1();
myform1.ShowDialog();
}
Could you please help a frustrated newbie, any questions I am happy to respond to.
Here is my FormLoad section
#region check internet when form opens
private void Form1_Load(object sender, EventArgs e)
{
notifyIcon1.Text = (playingToolStripMenuItem.Text);
checkTheInternet();
}
#endregion
Here is the Internet Checker Code called from the loadform
#region Check for Internet Connection Loop
private void checkTheInternet()
{
while (true)
{
bool con = NetworkInterface.GetIsNetworkAvailable();
if (con == false)
{
MessageBox.Show("No Internet Connection!");
playingToolStripMenuItem.Text = "No Internet Connection!";
notifyIcon1.Icon = radio_Off;
notifyIcon1.Visible = true;
return;
}
else
{
return;
}
}
}
#endregion
This is where the file selection starts
region Play MP3 List Automatically
private void mP3ToolStripMenuItem_Click(object sender, EventArgs e)
{
player.PlayStateChange += new WMPLib._WMPOCXEvents_PlayStateChangeEventHandler(player_PlayStateChange);
string[] files, paths;
OpenFileDialog oFD = new OpenFileDialog();
oFD.Multiselect = true;
oFD.Filter = "Music Files |*.mp3;*.wav";
if (oFD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
pauseToolStripMenuItem.Visible = true;
files = oFD.SafeFileNames;
for (int i = 0; i < files.Length; i++)
{
listBox1.Items.Add(paths[i]);
myCount = i + 1;
}
trackplayer();
}
}
If opening a new form is needed to play your song, I am not sure why since I do not have all your code, but you do not want multiple forms then do this. Create a private field which will hold a reference to your form:
private Form1 prevForm;
Change your myTempFormOpen to:
public void mytempFormOpen()
{
if (prevForm != null)
{
prevForm.Close();
}
prevForm = new Form1();
prevForm.ShowDialog();
}
Also myTempFormOpen should be MyTempFormOpen to follow .NET naming conventions.
Also in checkInternet method, you can return right away if connection is true instead of checking false first. Also, not sure why you need the while loop.
Let me know if that solves your issue.
I eventually found the answer by using a timer. The answer to the solution can be found here How to detect when a mp3 file has finished playing Big Thanks to all those that helped.

.NET DataSet not updating with new row

I am trying to add a new typed row in a DataTable and update it to the source but its not working
public partial class JobTableAdapter
{
public OpenMassSenderCore.OpenMassSenderDBDataSet.JobRow getNewRow()
{
return OpenMassSenderDBDataSet.getInstance().Job.NewJobRow();
}
public void submitRow(OpenMassSenderCore.OpenMassSenderDBDataSet.JobRow row)
{
OpenMassSenderDBDataSet.getInstance().Job.Rows.Add(row);
OpenMassSenderDBDataSet.getInstance().Job.AcceptChanges();
Update(OpenMassSenderDBDataSet.getInstance().Job);//thats the default tableadapter's update
}
private static JobTableAdapter instance;
public static JobTableAdapter getInstance()
{
if (instance == null) instance = new JobTableAdapter();
return instance;
}
}
private void button1_Click(object sender, EventArgs e)
{
OpenMassSenderCore.OpenMassSenderDBDataSet.JobRow job=JobTableAdapter.getInstance().getNewRow();
job.ID = 2;
job.query = "";
job.group = "smaplist1";
job.sender_account = 1;
job.status = OpenMassSenderCore.OpenMassSenderDBDataSet.JobRow.JobStatus.PENDING;
job.user = 1;
job.message =1;
JobTableAdapter.getInstance().submitRow(job);
}
If I press the button twice I get the key(ID) existing exception so this part works ok, the only problem is that its not updating the database(access)
Well, duh, you called AcceptChanges.
You basically said "Ok, this data is now committed, everything is fine. By the way, DataAdapter, can you commit all the changes on this dataset to the database? Thanks." "Sure, let me see... okay, your data set has no changes, so I'm done". You've thrown away the only information the data adapter can use to actually update the database :)
(As a side note - please, don't write Java in C#. It hurts. And DataSets are an ancient technology that wasn't updated in years, you might want to find something a bit more uptodate.)

Why isn't my entity framework deleting my record?

New to entity framework, but I would think this should be pretty simple.
My form load creates a context from my Entities. I create a list of clients and have a binding source that I assign clients to. The binding source is assigned to a Binding Navigator - clientBindingNavigator.
private void ClientExtForm_Load (object sender, EventArgs e)
{
_context = new IDVisitorEntities ();
List<IDVM.Client> clients = _context.Clients.ToList ();
clientBindingSource.DataSource = clients;
}
excerpt from ClientExtForm.Designer.cs
//
// clientBindingNavigator
//
this.clientBindingNavigator.AddNewItem = this.bindingNavigatorAddNewItem;
this.clientBindingNavigator.BindingSource = this.clientBindingSource;
this.clientBindingNavigator.CountItem = this.bindingNavigatorCountItem;
this.clientBindingNavigator.DeleteItem = this.bindingNavigatorDeleteItem;
this.clientBindingNavigator.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.bindingNavigatorMoveFirstItem,
this.bindingNavigatorMovePreviousItem,
this.bindingNavigatorSeparator,
this.bindingNavigatorPositionItem,
this.bindingNavigatorCountItem,
this.bindingNavigatorSeparator1,
this.bindingNavigatorMoveNextItem,
this.bindingNavigatorMoveLastItem,
this.bindingNavigatorSeparator2,
this.bindingNavigatorAddNewItem,
this.bindingNavigatorDeleteItem,
this.clientBindingNavigatorSaveItem});
When I click the Delete Button on the navigator tool bar the the ClientBindingSource.Count has been reduced by 1 .
private void clientBindingNavigatorSaveItem_Click (object sender, EventArgs e)
{
this.OnSave ();
}
public override void OnSave ()
{
foreach (ObjectStateEntry entry in _context.ObjectStateManager.GetObjectStateEntries (EntityState.Deleted))
{
// nothing shows up in this
}
foreach (ObjectStateEntry entry in _context.ObjectStateManager.GetObjectStateEntries (EntityState.Modified))
{
// when modified
}
foreach (ObjectStateEntry entry in _context.ObjectStateManager.GetObjectStateEntries (EntityState.Added))
{
// when adding this finds it
}
clientBindingSource.EndEdit ();
visitorHostsBindingSource.EndEdit ();
_context.SaveChanges ();
base.OnSave ();
}
It appears as though the navigator is removing the item from the collection.
Added info: It appears that in the navigator the DeleteItem button corresponds to the RemoveCurrent method (on click event calls it). Not sure how to tie in before the RemoveCurrent does it's thing.
What are my options for preforming the delete?
Removing an item from the clientBindingSource will have no effect on the item at the database level. You have to explicitly call _context.Clients.DeleteObject(deletedClient); You perform must all CRUD operations through the ObjectContext.
After looking around found some blogs that suggest to not use the default DeleteItem.
this.clientBindingNavigator.DeleteItem = null;//= this.bindingNavigatorDeleteItem;
In my case to make it clear for the BindingNavigator I replaced this.bindingNavigatorDeleteItem with a new button this.toolStripButton1 in the Items list.
this.clientBindingNavigator.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.bindingNavigatorMoveFirstItem,
this.bindingNavigatorMovePreviousItem,
this.bindingNavigatorSeparator,
this.bindingNavigatorPositionItem,
this.bindingNavigatorCountItem,
this.bindingNavigatorSeparator1,
this.bindingNavigatorMoveNextItem,
this.bindingNavigatorMoveLastItem,
this.bindingNavigatorSeparator2,
this.bindingNavigatorAddNewItem,
this.toolStripButton1,
this.clientBindingNavigatorSaveItem});
Creation of the new button looks like this:
//
// toolStripButton1
//
this.toolStripButton1.Image = ((System.Drawing.Image) (resources.GetObject ("bindingNavigatorDeleteItem.Image")));
this.toolStripButton1.RightToLeftAutoMirrorImage = true;
this.toolStripButton1.Name = "toolStripDeleteItem";
this.toolStripButton1.Size = new System.Drawing.Size(23, 22);
this.toolStripButton1.Text = "Delete";
this.toolStripButton1.Click += new System.EventHandler(this.toolStripButton1_Click);
The Click event then calls the RemoveCurrent (just like the default does) but I can get the current entity and stash it in an arrraylist for use on save.
private void toolStripButton1_Click (object sender, EventArgs e)
{
var currentclient = (Client) clientBindingSource.Current;
clientstodelete.Add (currentclient);
clientBindingSource.RemoveCurrent ();
}
I didn't need to create a new button, I just needed to have the this.clientBindingNavigator.DeleteItem not tied to a button. Because the DeleteItem creates a click event under the hood that calls the BindingSource.RemoveCurrent(). I might change the button back to the default one created but for illustration wanted everyone to see what was happening.
I agree it seemed odd to have to delete the record from the table directly if I had just deleted using RemoveCurrent(). But it is what it is... This took care of the record in the datagridview and the datasource in one clean sweep.
Here is how I solved the problem:
t_StaffDaysOff sdo = (t_StaffDaysOff)t_StaffDaysOffbindingSource.Current;
t_StaffDaysOffbindingSource.RemoveCurrent();
t_StaffDaysOffbindingSource.EndEdit();
db.t_StaffDaysOff.Remove(sdo);
db.SaveChanges();

How to stop method from calling themselves recursively?

I have two tables, employees and project, in listbox2, I show all the employees and in listbox1 all the projects, now obviously one employee can be involved in many projects and one project could have many employee. So I have this EmployeeProject that maps the many to many relation that exists. What I want is, if user click a project name in first listbox, then all employees in that project should be selected in listbox2. Also, when a user clicks a item in listbox2, (an employee) all project of which that employee is a part should be selected in listbox1
But If I use ListBox.SelectedIndexChanged event for this process, and select even a single value in listbox2 then it would trigger the SelectedIndexChagned for listbox2, and that would start working by selecting all items in listbox1 that current employee is a part of, but again, as soon as even one item in listbox1 is selected, it would fire up its SelectedIndexChanged event, and it would go on forever like this. So what's the solution of this? So far, I've done this..
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// Load the list of employees
cmd.CommandText =
"SELECT EmpName FROM Employee WHERE EmpID IN(SELECT EmpID FROM EmployeeProject WHERE ProjectID =(SELECT ProjectID FROM Project WHERE ProjectName = '" +
listBox1.SelectedItem.ToString() + "')) ORDER BY EmpId";
var rdr = cmd.ExecuteReader();
listBox2.Items.Clear();
// right now, I am doing this to escape this recursive loop, but thats not what I want
while (rdr.Read())
{
listBox2.Items.Add(rdr.GetString(0));
}
rdr.Close();
this.AutoScroll = true;
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
// Load the list of projects
cmd.CommandText =
"SELECT ProjectName FROM Projects WHERE ProjectID IN(SELECT ProjectID FROM EmployeeProject WHERE EmpId=(SELECT EmpId FROM Employee WHERE EmpName= '" +
listBox2.SelectedItem.ToString() + "')) ORDER BY ProjectID";
var rdr = cmd.ExecuteReader();
listBox1.Items.Clear();
// again, I don't want to clear, but select all those employee in listbox1 that are involved in this selected project, but can't do it because it would cause infinite recursion of these
while (rdr.Read())
{
listBox2.Items.Add(rdr.GetString(0));
}
rdr.Close();
this.AutoScroll = true;
}
So? What should I do to achieve what I want to achieve? And how would I avoid that recursion? I know this way also works what I just showed, but I don't want to clear up and show up again, (this might confuse a simple user). I want for each selection, values corresponding to that selection be selected in other listbox (without causing recursion of course!). How do I do it?
EDIT I don't know how can I select multiple items in listbox programmatically, so if you could tell that, it would be great!
There is a design pattern called Balking, I think it applies here.
http://en.wikipedia.org/wiki/Balking_pattern
The idea is to introduce an auxiliary state variable to control the operation:
private bool doesProcessing { get; set; }
private void listBox1_SelectedIndexChanging( ... )
{
// signal the beginning of processing
if ( doesProcessing )
return;
else
doesProcessing = true;
try
{
// your logic goes here
}
finally
{
// signal the end of processing
doesProcessing = false;
}
}
and the same for listBox2.
When you change the selected items of one listbox, you could temporarily disable the events on the other. For example:
// Store the event handlers in private member variables.
private System.EventHandler selectedEmployeeChanged = new System.EventHandler(this.lbEmployees_SelectedIndexChanged);
private void lbProjects_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
// Remove your event so that updating lbEmployees doesn't cause
// lbEmployees_SelectedIndexChanged to get fired.
lbEmployees.SelectedIndexChanged -= selectedEmployeeChanged;
// other event handler logic
}
finally
{
// Ensure that the handler on lbEmployees is re-added,
// even if an exception was encountered.
lbEmployees.SelectedIndexChanged += selectedEmployeeChanged;
}
}
Note: I have renamed your listBoxes (and the associated events) to be more readable. As per your description, listBox1 is now lbEmployees and listBox2 is now lbProjects.
As for programatically selecting multiple items, if you know the index for each one, you could use the ListBox.SetSelected Method. For example:
listBox1.SetSelected(1, true);
listBox1.SetSelected(3, true);
causes listBox1 to select the items at 1 and 3.
In your case, I would recomend only using the queries to get what values to select (not clearing your listboxes and then just adding back the values that should be selected). Below is my suggestion for how you would rewrite one of your handlers:
// Store the event handlers in private member variables.
private System.EventHandler selectedEmployeeChanged = new System.EventHandler(this.lbEmployees_SelectedIndexChanged);
private void lbProjects_SelectedIndexChanged(object sender, EventArgs e)
{
// Declare this outside of try so that we can close it in finally
DbDataReader reader = null;
try
{
// Remove your event so that updating lbEmployees doesn't cause
// lbEmployees_SelectedIndexChanged to get fired.
lbEmployees.SelectedIndexChanged -= selectedEmployeeChanged;
// Deselect all items in lbEmployees
lbEmployees.ClearSelected();
cmd.CommandText = "SELECT ProjectName FROM Projects WHERE ProjectID IN(SELECT ProjectID FROM EmployeeProject WHERE EmpId=(SELECT EmpId FROM Employee WHERE EmpName= '#EmpName')) ORDER BY ProjectID";
cmd.Parameters.AddWithValue("#EmpName", lbProjects.SelectedItem.ToString());
reader = cmd.ExecuteReader();
// For each row returned, find the index of the matching value
// in lbEmployees and select it.
while (rdr.Read())
{
int index = lbEmployees.FindStringExact(rdr.GetString(0));
if(index != ListBox.NoMatches)
{
lbEmployees.SetSelected(index, true);
}
}
this.AutoScroll = true;
}
finally
{
// Ensure that the reader gets closed, even if an exception ocurred
if(reader != null)
{
reader.Close();
}
// Ensure that the handler on lbEmployees is re-added,
// even if an exception was encountered.
lbEmployees.SelectedIndexChanged += selectedEmployeeChanged;
}
}
As a side note, you may want to look into using a JOIN operator in your query string, rather than multiple nested SELECTS.
You can remove the attached event to one of the controls when you are in the other, before doing any modifications.
then reattach at the end.
Have one eventMask integer variable and use the pattern below to protect your event each other.
Using a bool as suggested in another answer is enough for this scenario. However, I prefer to use an integer rather than a bool : it can handle nested and stacked events calls correctly.
It is particularly useful when I have to deal with selection/deselection events in treeviews and listviews for example.
int eventMask = 0;
void items_PropertyChanged(object sender, PropertyChangedEventArgs e) // for example...
{
if (eventMask > 0)
return;
try
{
eventMask++;
// processing
// it happens some other events can be called. Including this one.
}
finally
{
// put this in finally, so there is no lock risk
eventMask--;
}
}
The logic of the OP code (if working as OP expect) contains a problem.
Suppose you fill the two lists with all possible values.
Then, when the user clicks on one item, the second list is emptied and filled only with the item linked to the other list. But clicking between the two list could remove forever one or more item from the other list. It is better to leave the two list filled and trying to highlight the line of the corresponding items
For example (supposing ListBox.SelectionMode = SelectionMode.MultiSimple or MultiExtended)
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
........
try
{
......
// Remove the event handler, do your selection, No event on the listbox2 will be fired....
listBox2.SelectedIndexChanged -= new System.EventHandler(this.listBox2_SelectedIndexChanged);
// Do not remove the items , instead clear previous selection
listBox2.ClearSelected();
while (rdr.Read())
{
int index = listBox2.FindString(rdr.GetString(0), -1);
if(index != -1) listBox2.SetSelected(index, true));
}
....
}
finally
{
// before exit, reapply the event handler
listBox2.SelectedIndexChanged += new System.EventHandler(this.listBox2_SelectedIndexChanged);
}
}
of course you need to be sure to reapply the event, so use a try/finally block
The same approach will be valid to stop the event firing for listBox1 when you fill it in the listBox2.SelectedIndexChanged event,

Categories