diff --git a/Source/Libation.sln b/Source/Libation.sln index 90240fa8..3bb961ef 100644 --- a/Source/Libation.sln +++ b/Source/Libation.sln @@ -5,6 +5,7 @@ VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution Items", "_Solution Items", "{03C8835F-936C-4AF7-87AE-FF92BDBE8B9B}" ProjectSection(SolutionItems) = preProject + __ARCHITECTURE NOTES.txt = __ARCHITECTURE NOTES.txt __README - COLLABORATORS.txt = __README - COLLABORATORS.txt __TODO.txt = __TODO.txt _DB_NOTES.txt = _DB_NOTES.txt diff --git a/Source/LibationWinForms/grid/AsyncNotifyPropertyChanged.cs b/Source/LibationWinForms/grid/AsyncNotifyPropertyChanged.cs index 87d3a52c..b1711915 100644 --- a/Source/LibationWinForms/grid/AsyncNotifyPropertyChanged.cs +++ b/Source/LibationWinForms/grid/AsyncNotifyPropertyChanged.cs @@ -6,6 +6,7 @@ namespace LibationWinForms { public abstract class AsyncNotifyPropertyChanged : SynchronizeInvoker, INotifyPropertyChanged { + // see also notes in Libation/Source/__ARCHITECTURE NOTES.txt :: MVVM public event PropertyChangedEventHandler PropertyChanged; // per standard INotifyPropertyChanged pattern: diff --git a/Source/LibationWinForms/grid/ProductsGrid.cs b/Source/LibationWinForms/grid/ProductsGrid.cs index b088262e..d3514dda 100644 --- a/Source/LibationWinForms/grid/ProductsGrid.cs +++ b/Source/LibationWinForms/grid/ProductsGrid.cs @@ -231,6 +231,7 @@ namespace LibationWinForms { var entry = new GridEntry(libraryBook); entry.Committed += reapplyFilter; + // see also notes in Libation/Source/__ARCHITECTURE NOTES.txt :: MVVM entry.LibraryBookUpdated += (sender, _) => _dataGridView.InvalidateRow(_dataGridView.GetRowIdOfBoundItem((GridEntry)sender)); return entry; } diff --git a/Source/__ARCHITECTURE NOTES.txt b/Source/__ARCHITECTURE NOTES.txt new file mode 100644 index 00000000..966713fe --- /dev/null +++ b/Source/__ARCHITECTURE NOTES.txt @@ -0,0 +1,14 @@ +MVVM +==== +Libation is not strictly MVVM. It's not strictly anything. There are however efforts at moving some major components toward this pattern. + +Primary View: ProductsGrid +Primary View Model: GridEntry + +see also: https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/raise-change-notifications--bindingsource +BindingSource + INotifyPropertyChanged + DataGridView is the backbone of our implementation. The SortableBindingList (BindingList/BindingSource) automatically subscribes to each entry's NotifyPropertyChanged -- which is why our AsyncNotifyPropertyChanged.NotifyPropertyChanged is needed even though none of our code calls it. + +- Adding or removing an entry to/from this BindingSource automatically updates the UI. No additional code needed. +- Updating a field updates the UI via calling NotifyPropertyChanged. + +We break the pattern with updating the book inside of GridEntry. To really follow MVVM, iterate through every bound ("binded"?) field name and call NotifyPropertyChanged. It's much more convenient, quicker, and less error prone to make an exception to MVVM via GridEntry.LibraryBookUpdated => InvalidateRow. The downside is that the view has to wire this up. If we change where in the code we can update the book inside of GridEntry, this dependency will also need to be duplicated in the new place