Reputation: 1
I have two Datagridviews in my form, one of them shows list of "authors"(name) and the other one shows list of books (title ,author, year, price). in form load it show all the books, but i want when user clicks on author name on first datagridview, data in second datagridview update and just show books rlated to selected author.
also first field of author's list should be "ALL" so user be able to list all the books even after filtering by author.
sorry for my bad English
Upvotes: 0
Views: 56
Reputation: 30464
So internally you have collections of Authors
and Books
. Somehow, probably by foreign key, there is a link between Authors and Books: if you have an Author, you can get all his Books, and the other way, if you have a Book, you can get his Author.
Classes will be similar to the following:
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;}
}
These classes look very similar to the classes that you would have when you'd use entity framework. However, the database tables won't have the virtual functions. If you don't use entity framework, you'll have to write the virtual functions yourself. Consider adding them as extention methods. This way you can keep your classes similar to your tables. If you are not familiar with extension methods, read Extension Methods demystified.
Using the designer, you added two DataGridViews, one that will display some properties of all Authors, and one that will display some properties of the Books written by the selected Author.
Using the designer you've also added the columns that you want to show in your DataGridViews.
Using property DataGridViewColumn.DataPropertyName you define which column will show which property. You can do this using the designer, I prefer to do this in the constructor of the form.
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);
...
Your form needs some methods to get Authors and Books from your database:
public IEnumerable<Author> GetAllAuthors();
public IEnumerable<Book> GetBooksOfAuthor(int authorId);
The implementation depends on how you store your Authors and Books. I'll let you do the implementation.
Properties to get and set the contents of the DataGridViews:
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;
}
To initially show all Authors, and no Books (no Author has been selected yet):
public void InitializeDataGridViews()
{
this.DisplayedAuthors = new BindingList<Author>(this.GetAllAuthors().ToList());
this.DisplayedBooks = null; // it might be that you need to assign empty array
}
Apparently you need properties to get the selected Author. When I add a DataGridView to my form, I always add the following two properties:
public IEnumerable<Author> SelectedAuthors => this.DataGridViewAuthors.SelectedRows
.Cast<DataGridViewColumn>()
.Select(row => row.DataBoundItem)
.Cast<Author>();
In words: to get all SelectedAuthors (might be more than one), get all SelectedRows from the DataGridViewAuthors. Cast this to a sequence of DataGridViewRows. From every DataGridViewRow get the value of its DataBoundItem. Because I use only property DisplayedAuthors to show the Authors, I know that every DataBoundItem is an Author, hence I can cast every fetched DataBoundItem to an Author.
I also need a property to fetch the current Author:
public Author CurrentAuthor => (Author)this.DataGridViewAuthors.CurrentRow.DataBoundItem;
For Books I can do the same:
public IEnumerable<Author> SelectedBooks => this.DataGridViewBooks.SelectedRows
.Cast<DataGridViewColumn>()
.Select(row => row.DataBoundItem)
.Cast<Book>();
public Author CurrentBook =>
(Book)this.DataGridViewBooks.CurrentRow.DataBoundItem;
The above seems like a lot of code. However, all methods and properties are only one or two lines of codes. They are easy to understand, easy to change, and maintain, easy to reuse, and easy to unit test.
After all these properties showing the Books of the selected author can also be written in one line. For ease of understanding I'll make it three lines:
public void DisplayBooksOfSelectedAuthor()
{
Author selectedAuthor = this.SelectedAuthor;
IEnumerable<Book> booksOfSelectedAuthor = this.GetBooksOfAuthor(selectedAuthor.Id);
this.DisplayedBooks = new BindingList<Book>(booksOfSelectedAuthor.ToList());
}
Almost there
Subscribe to event DataGridView.SelectionChanged
public void OnDataGridViewAuthorSelectionChanged(object sender, ...)
{
this.DisplayBooksOfSelectedAuthor();
}
A one liner method, this should not come as a surprise by now.
These methods are all very small, easy to understand, easy to maintain and change, easy to reuse and unit test.
Upvotes: 0
Reputation: 21
Use Cellclick Event Of datagridview1 c#
Get author The Cell Value of author Column
then u should search books by author(maybe got List)
then set List to DataSource of datagridview2
Upvotes: 0