Доброго дня вам!
По ходу у меня становится традицией отписываться на статьи...
В нарушение традициии эта приятно порадовала — умеют же если захотят. Как всегда — пустые придирки к коду. Ничего серьёзного — это ж сампл, не продакшн. Не обращяйте внимания и пишите ещё
1) Мелочь:
public event EventHandler<EventArgs> AuthorChanged;
Зачем здесь генерик-версия? Кстати, правило хорошего тона — заодно реализовать INotifyPropertyChanged.
2) Совсем пустая придирка:
if (AuthorChanged != null)
AuthorChanged(this, EventArgs.Empty);
Выносится в отдельный метод. Да, проверка на нулл может не сработать при многопоточности. Перед проверкой кэшируйте в локальной переменной.
3) Ещё мелочь:
bookInfo.AuthorChanged += (s, e) =>
{
authorTextBox.Text = ((BookInfo)s).Author;
};
Где отписка от событий?

Или сущности буду жить меньше формы?
4) И ещё:
public CustomBinder(Control control, string controlPropertyName,
object dataSource, string dataSourcePropertyName)
{
...
}
Во-первых, поаккуратнее с исключениями в конструкторе — лучше Factory сделать. Во-вторых сначала стоит проверить на свойства сорс и таргет, и только потом подписываться на события. Опять, где отписка?

И почему CustomBinder не IDisposable?
5) А кто лайфтаймом биндингов управлять будет?

Не, я понимаю, что оно будет жить вечно...
private void Bind()
{
CustomBinder authorPropertyManager =
new CustomBinder(authorTextBox, "Text", bookInfo, "Author");
CustomBinder titlePropertyManager =
new CustomBinder(titleTextBox, "Text", bookInfo, "Title");
CustomBinder isbnPropertyManager =
new CustomBinder(isbnTextBox, "Text", bookInfo, "ISBN");
CustomBinder pageCountPropertyManager =
new CustomBinder(pageCountTextBox, "Text", bookInfo, "PageCount");
CustomBinder publisherPropertyManager =
new CustomBinder(publisherTextBox, "Text", bookInfo, "Publisher");
}
Дальше есть ещё пара мелких косяков, наподобие непроверки IndexOf(...) на -1, если интересно — найдёте сами.
Удачи!