如何使用按钮软删除 DataGrid 视图中的选定行
How to soft delete a selected row in a DataGrid View using a button
所以我有一个名为 MyMovieDataDrid 的 DataGridView,它连接到一个 sql 服务器,我已经有了我的 IsDeleted 属性,顺便说一句,我的 IsDeleted 有一个删除存储库,如下所示属性 自动显示为一个复选框,因此如果复选框被选中,则为 true,否则为 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;
}
这是我的删除按钮方法,所以当我按下它时,它 运行 是我的逻辑并从 DataGridView 中软删除一行我已经尝试了多种解决方案,例如使用选定的行事件处理程序来获取选定的行然后 运行 使用存储库方法,但 none 到目前为止有效。
private void DeleteButton_Click(object sender, EventArgs e)
{
Movie movie = new Movie();
if(MyMovieDataGrid.SelectedRow.Count > 0)
{
_movieRepo.DeleteMovie(movie.Id);
}
}
和我所有的财产
Movie movie = new Movie()
{
Id = Guid.NewGuid(),
IsDeleted = false,
MovieNames = MovieNameBox.Text;
}
和我的 AddMovie 存储库
public void AddMovie(Movie movie)
{
_context.Movie.Add(movie);
_context.SaveChanges();
}
电影存储库方法
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();
所以我的问题是如何让我的 Datagrid 知道何时 运行 我的存储库方法,我觉得我必须以某种方式写一些代码到如果 IsDeleted 属性 为真它选择整行然后我 运行 我的 DeleteMovie 方法但没有解决方案有效。
考虑在 OnModelCreating
中设置一个过滤器,在这种情况下,我使用的是一个名为 Contact1
的模型,因为我已经有了它。在底层 table 添加 IsDeleted
列但不在模型中。
下面显示了软删除行并将其从 DataGridView 中删除的基础知识。没有合适的存储库。
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);
然后 override SaveChanges
在 DbContext
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new ())
{
DoShadowyStuff();
return base.SaveChangesAsync(cancellationToken);
}
public override int SaveChanges()
{
DoShadowyStuff();
return base.SaveChanges();
}
然后在 DoShadowlyStuff
中,如果状态为 Deleted,则将状态设置为 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;
}
}
}
非常基本的 read
和 delete
操作
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();
}
}
}
基本的表单操作。单击删除按钮,将当前行的状态设置为已删除,保存将联系人标记为已修改并设置 isDeleted 的更改。接下来从 BindingList 中删除 remove,这又从 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);
}
}
我喜欢 Karen 的方法更“应该如何完成”,但它与您编写的内容相去甚远,我怀疑您可能不想大量更改当前代码
你的方法的基本问题是你没有从被点击的行中获取电影 ID,你制作了一部新电影,它有一个新的随机 Guid,据说保证根本不在数据库中因为 Guid 不太可能重复,然后你尝试删除它:
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);
}
}
这意味着你要删除的电影实际被删除的几率是惊人的5316911983139663491615228241121400000比1;如果您现在开始点击并继续前进,直到地球被变成红巨星的太阳吞没,这可能不会发生
从点击的行中检索要删除的Guid;添加一个 CellContentClicked 处理程序并检查它是被单击的已删除按钮列,然后将电影 ID 从该行的数据绑定项中拉出:
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);
}
}
所以我有一个名为 MyMovieDataDrid 的 DataGridView,它连接到一个 sql 服务器,我已经有了我的 IsDeleted 属性,顺便说一句,我的 IsDeleted 有一个删除存储库,如下所示属性 自动显示为一个复选框,因此如果复选框被选中,则为 true,否则为 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;
}
这是我的删除按钮方法,所以当我按下它时,它 运行 是我的逻辑并从 DataGridView 中软删除一行我已经尝试了多种解决方案,例如使用选定的行事件处理程序来获取选定的行然后 运行 使用存储库方法,但 none 到目前为止有效。
private void DeleteButton_Click(object sender, EventArgs e)
{
Movie movie = new Movie();
if(MyMovieDataGrid.SelectedRow.Count > 0)
{
_movieRepo.DeleteMovie(movie.Id);
}
}
和我所有的财产
Movie movie = new Movie()
{
Id = Guid.NewGuid(),
IsDeleted = false,
MovieNames = MovieNameBox.Text;
}
和我的 AddMovie 存储库
public void AddMovie(Movie movie)
{
_context.Movie.Add(movie);
_context.SaveChanges();
}
电影存储库方法
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();
所以我的问题是如何让我的 Datagrid 知道何时 运行 我的存储库方法,我觉得我必须以某种方式写一些代码到如果 IsDeleted 属性 为真它选择整行然后我 运行 我的 DeleteMovie 方法但没有解决方案有效。
考虑在 OnModelCreating
中设置一个过滤器,在这种情况下,我使用的是一个名为 Contact1
的模型,因为我已经有了它。在底层 table 添加 IsDeleted
列但不在模型中。
下面显示了软删除行并将其从 DataGridView 中删除的基础知识。没有合适的存储库。
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);
然后 override SaveChanges
在 DbContext
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new ())
{
DoShadowyStuff();
return base.SaveChangesAsync(cancellationToken);
}
public override int SaveChanges()
{
DoShadowyStuff();
return base.SaveChanges();
}
然后在 DoShadowlyStuff
中,如果状态为 Deleted,则将状态设置为 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;
}
}
}
非常基本的 read
和 delete
操作
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();
}
}
}
基本的表单操作。单击删除按钮,将当前行的状态设置为已删除,保存将联系人标记为已修改并设置 isDeleted 的更改。接下来从 BindingList 中删除 remove,这又从 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);
}
}
我喜欢 Karen 的方法更“应该如何完成”,但它与您编写的内容相去甚远,我怀疑您可能不想大量更改当前代码
你的方法的基本问题是你没有从被点击的行中获取电影 ID,你制作了一部新电影,它有一个新的随机 Guid,据说保证根本不在数据库中因为 Guid 不太可能重复,然后你尝试删除它:
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);
}
}
这意味着你要删除的电影实际被删除的几率是惊人的5316911983139663491615228241121400000比1;如果您现在开始点击并继续前进,直到地球被变成红巨星的太阳吞没,这可能不会发生
从点击的行中检索要删除的Guid;添加一个 CellContentClicked 处理程序并检查它是被单击的已删除按钮列,然后将电影 ID 从该行的数据绑定项中拉出:
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);
}
}