'How to soft delete a selected row in a DataGrid View using a button
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.
Solution 1:[1]
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);
}
}
Solution 2:[2]
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);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Caius Jard |
Solution 2 | Karen Payne |