I use a BindingNavigator to delete items from the products list, via the datagridview. (The methodcall main.DeleteProduct() calls a repository to delete from database).
I need some help to improve the code of the ..DeleteItem_Click event. When I click on a cell/or row, and then delete button (BindingNavigator), it never deletes that row. It deletes the row below, or if it's the last row, the row above, and if only one row, a null is cast. Shouldn't the bindingSource.Current be same item as currentrow of datagridview?
Also, is the way I'm casting the current item 开发者_如何学Pythonusing the bindingsource a good way? Would appretiate better code suggestion if you have.
Cheers!
public partial class Form1 : Form
{
private MainBL main = new MainBL();
private List<Product> products = new List<Product>
private void Form1_Load(object sender, EventArgs e)
{
bsProducts.DataSource = products; // BindingSource
bnProducts.BindingSource = bsProducts; // BindingNavigator
dataGridView1.DataSource = bsProducts; //
}
private void bindingNavigatorDeleteItem_Click(object sender, EventArgs e)
{
Product product = (Product)bsProducts.Current;
// Putting a breakpoint here, shows the identity property is not the same
// as row selected in datagridview.
main.DeleteProduct(product);
}
A better solution is probably to intercept/remove the Binding Navigator's delete event, and to handle the deletion manually.
Go to the Binding Navigator; Bring up the properties in the Properties window. Find the DeleteItem property (under the "Items" category), and set it to "(none)".
Now you can code the deletion functionality in the click event of delete button in the associated toolbar. The code in the previous answer will work - you can now get the correct "current" item. You can add a confirmation check ("Are you sure?") here as well if required.
Of course, do not forget to remove the item from the collection to which the BindingSource is bound (or just refresh the data).
I understood now that the row is deleted before the CellClick event fires. So I make it work as intended by instead putting the code in the _MouseDown event of the delete button. Not sure if this is the most proper solution though..
private void btnDeleteProducts_MouseDown(object sender, MouseEventArgs e)
{
Product product = (Product)bsProducts.Current;
if (product != null)
{
main.DeleteProduct(product);
}
}
I came across this and did something similar to what OP [bretddog] did, but I wrote a more complete method.
I share my work here:
public class YourDataItem
{
// put all of your data here. This is just stubbed here as an example
public int Id { get; set; }
public String Description { get; set; }
}
private void DeleteBtn_Down(Object sender, MouseEventArgs e)
{
var item = (YourDataItem)bindingSource1.Current;
var dr = DialogResult.None;
if (0 < item.Id)
{
var ask = String.Format("Delete Item [{0}]?", item.Description);
dr = MessageBox.Show(ask, "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
}
if (dr == DialogResult.Yes)
{
try
{
bindingSource1.EndEdit();
_datamodel.YourDataItems.DeleteOnSubmit(item);
_datamodel.SubmitChanges();
_datamodel.ClearCache();
bindingSource1.SetPosition<YourDataItem>(x => x.Id == 0);
} catch (Exception err)
{
MessageBox.Show("Database changes failed to complete.", String.Format("Delete {0}", err.GetType()), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
} else
{
bindingSource1.CancelEdit();
}
}
A Linq data source can time out.
If someone hits a delete button as he is walking home for the day, comes in the next day and clicks "OK" on the confirmation dialog box, the try...catch
will handle the Object Disposed Exception.
ClearCache()
is just a well-known DataContext extension:
/// <summary>
/// Clears the cache from a DataContext to insure data is refreshed
/// </summary>
/// <param name="dc"></param>
public static void ClearCache(this DataContext dc)
{
dc.GetType().InvokeMember("ClearCache", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, dc, null);
}
精彩评论