如何使用按钮软删除 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;
        }
    }
}

非常基本的 readdelete 操作

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);
    }
}