我的表单中有两个 Datagridview,其中一个显示“作者”(姓名)列表,另一个显示书籍列表(书名、作者、年份、价格)。 在表单加载中,它显示所有书籍,但我希望当用户单击第一个 datagridview 上的作者姓名时,第二个 datagridview 中的数据更新并仅显示与所选作者相关的书籍。
作者列表的第一个字段应该是“ALL”,这样用户即使在按作者过滤后也能够列出所有书籍。
抱歉我的英语不好
使用datagridview1 c#的Cellclick事件
获取作者作者列的单元格值
那么你应该按作者搜索书籍(也许有列表)
然后将List设置为datagridview2的DataSource
所以在内部你有
Authors
和 Books
的集合。不知何故,可能通过外键,作者和书籍之间存在链接:如果您有一个作者,您可以获取他所有的书籍,反之,如果您有一本书,您可以获取他的作者。
课程将类似于以下内容:
class Author
{
public int Id {get; set;}
public string Name {get; set;}
... // other properties, Birthday? Bankaccount? Address?
// Every Author has written zero or more Books
public virtual ICollection<Book> Books {get; set;}
}
class Book
{
public int Id {get; set;}
public string Title {get; set;}
public DateTime PublicationDate {get; set;}
public decimal Price {get; set;}
// every Book is written by exactly one Author, using foreign key
public int AuthorId {get; set;}
public virtual Author Author {get; set;}
}
这些类看起来与使用实体框架时拥有的类非常相似。但是,数据库表不会有虚拟函数。如果不使用实体框架,则必须自己编写虚拟函数。考虑将它们添加为扩展方法。这样您就可以使您的课程与您的表格保持相似。如果您不熟悉扩展方法,请阅读扩展方法揭秘。
使用设计器,您添加了两个 DataGridView,一个将显示所有作者的一些属性,另一个将显示所选作者撰写的书籍的一些属性。
使用设计器,您还添加了要在 DataGridView 中显示的列。
使用属性 DataGridViewColumn.DataPropertyName 您可以定义哪个列将显示哪个属性。您可以使用设计器来执行此操作,我更喜欢在表单的构造函数中执行此操作。
class MyForm
{
public MyForm()
{
this.InitializeComponents();
// Define which column should show which Author properties:
columnAuthorsName.DataPropertyName = nameof(Author.Name);
// if needed, add other columns, for example:
columnAuthorsBirthDay.DataPropertyName = nameof(Author.BirthDay);
// Do the same for the Books:
columnBooksTitle.DataPropertyName = nameof(Book.Title);
columnBooksPrice.DataPropertyName = nameof(Book.Price);
...
您的表单需要一些方法来从数据库中获取作者和书籍:
public IEnumerable<Author> GetAllAuthors();
public IEnumerable<Book> GetBooksOfAuthor(int authorId);
实施取决于您存储作者和书籍的方式。我会让你来实施。
获取和设置 DataGridView 内容的属性:
public BindingList<Author> DisplayedAuthors
{
get => (BindingList<Author>)this.DataGridViewAuthors.DataSource;
set => this.DataGridViewAuthors.DataSource = value;
}
public BindingList<Book> DisplayedBooks
{
get => (BindingList<Book>)this.DataGridViewBooks.DataSource;
set => this.DataGridViewBooks.DataSource = value;
}
最初显示所有作者,但不显示书籍(尚未选择任何作者):
public void InitializeDataGridViews()
{
this.DisplayedAuthors = new BindingList<Author>(this.GetAllAuthors().ToList());
this.DisplayedBooks = null; // it might be that you need to assign empty array
}
显然您需要属性来获取选定的作者。当我向表单添加 DataGridView 时,我总是添加以下两个属性:
public IEnumerable<Author> SelectedAuthors => this.DataGridViewAuthors.SelectedRows
.Cast<DataGridViewColumn>()
.Select(row => row.DataBoundItem)
.Cast<Author>();
换言之:要获取所有 SelectedAuthors(可能不止一个),请从 DataGridViewAuthors 获取所有 SelectedRow。将其转换为 DataGridViewRows 序列。从每个 DataGridViewRow 获取其 DataBoundItem 的值。因为我只使用 DisplayedAuthors 属性来显示作者,所以我知道每个 DataBoundItem 都是一个作者,因此我可以将每个获取的 DataBoundItem 转换为一个作者。
我还需要一个属性来获取当前作者:
public Author CurrentAuthor => (Author)this.DataGridViewAuthors.CurrentRow.DataBoundItem;
对于书籍我也可以这样做:
public IEnumerable<Author> SelectedBooks => this.DataGridViewBooks.SelectedRows
.Cast<DataGridViewColumn>()
.Select(row => row.DataBoundItem)
.Cast<Book>();
public Author CurrentBook =>
(Book)this.DataGridViewBooks.CurrentRow.DataBoundItem;
上面看起来代码很多。然而,所有的方法和属性都只是一两行代码。它们易于理解、易于更改和维护、易于重用且易于进行单元测试。
显示所选作者的书籍的所有这些属性也可以写在一行中。为了便于理解,我将其分为三行:
public void DisplayBooksOfSelectedAuthor()
{
Author selectedAuthor = this.SelectedAuthor;
IEnumerable<Book> booksOfSelectedAuthor = this.GetBooksOfAuthor(selectedAuthor.Id);
this.DisplayedBooks = new BindingList<Book>(booksOfSelectedAuthor.ToList());
}
快到了
订阅事件 DataGridView.SelectionChanged
public void OnDataGridViewAuthorSelectionChanged(object sender, ...)
{
this.DisplayBooksOfSelectedAuthor();
}
单线方法,现在这应该不足为奇。
这些方法都非常小,易于理解,易于维护和更改,易于重用和单元测试。