diff --git a/Source/LibationWinForms/AvaloniaUI/Controls/DataGridCheckBoxColumnExt.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Controls/DataGridCheckBoxColumnExt.axaml.cs index be8157a0..9e82e369 100644 --- a/Source/LibationWinForms/AvaloniaUI/Controls/DataGridCheckBoxColumnExt.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Controls/DataGridCheckBoxColumnExt.axaml.cs @@ -1,35 +1,15 @@ using Avalonia.Controls; +using Avalonia.Controls.Utils; using Avalonia.Interactivity; using LibationWinForms.AvaloniaUI.ViewModels; +using System; +using System.Linq; namespace LibationWinForms.AvaloniaUI.Controls { - /// The purpose of this extension is to immediately commit any check state changes to the viewmodel + /// The purpose of this extension WAS to immediately commit any check state changes to the viewmodel, but for the life of me I cannot get it to work! public partial class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn { - protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem) - { - var ele = base.GenerateEditingElementDirect(cell, dataItem) as CheckBox; - ele.Checked += EditingElement_Checked; - ele.Unchecked += EditingElement_Checked; - ele.Indeterminate += EditingElement_Checked; - return ele; - } - - private void EditingElement_Checked(object sender, RoutedEventArgs e) - { - if (sender is CheckBox cbox && cbox.DataContext is GridEntry2 gentry) - { - gentry.Remove = cbox.IsChecked; - FindDataGridParent(cbox)?.CommitEdit(DataGridEditingUnit.Cell, false); - } - } - - DataGrid? FindDataGridParent(IControl? control) - { - if (control?.Parent is null) return null; - else if (control?.Parent is DataGrid dg) return dg; - else return FindDataGridParent(control?.Parent); - } + } } diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/BookTags.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/BookTags.cs index ab9717d4..cf2c7664 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/BookTags.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/BookTags.cs @@ -2,8 +2,8 @@ { public class BookTags { - public string Tags { get; init; } - public bool IsSeries { get; init; } - public bool HasTags => !string.IsNullOrEmpty(Tags); + private string _tags; + public string Tags { get => _tags; init { _tags = value; HasTags = !string.IsNullOrEmpty(_tags); } } + public bool HasTags { get; init; } } } diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/GridEntry2.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/GridEntry2.cs index afd46f72..21e684b1 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/GridEntry2.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/GridEntry2.cs @@ -21,7 +21,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels SomeRemoved } /// The View Model base for the DataGridView - public abstract class GridEntry2 : AsyncNotifyPropertyChanged2, IMemberComparable + public abstract class GridEntry2 : ViewModelBase { [Browsable(false)] public string AudibleProductId => Book.AudibleProductId; [Browsable(false)] public LibraryBook LibraryBook { get; protected set; } @@ -32,30 +32,35 @@ namespace LibationWinForms.AvaloniaUI.ViewModels #region Model properties exposed to the view + private Avalonia.Media.Imaging.Bitmap _cover; + private string _purchaseDate; + private string _series; + private string _title; + private string _length; + private string _authors; + private string _narrators; + private string _category; + private string _misc; + private string _description; + private string _productRating; + private string _myRating; + public Avalonia.Media.Imaging.Bitmap Cover { get => _cover; protected set { this.RaiseAndSetIfChanged(ref _cover, value); } } + public string PurchaseDate { get => _purchaseDate; protected set { this.RaiseAndSetIfChanged(ref _purchaseDate, value); } } + public string Series { get => _series; protected set { this.RaiseAndSetIfChanged(ref _series, value); } } + public string Title { get => _title; protected set { this.RaiseAndSetIfChanged(ref _title, value); } } + public string Length { get => _length; protected set { this.RaiseAndSetIfChanged(ref _length, value); } } + public string Authors { get => _authors; protected set { this.RaiseAndSetIfChanged(ref _authors, value); } } + public string Narrators { get => _narrators; protected set { this.RaiseAndSetIfChanged(ref _narrators, value); } } + public string Category { get => _category; protected set { this.RaiseAndSetIfChanged(ref _category, value); } } + public string Misc { get => _misc; protected set { this.RaiseAndSetIfChanged(ref _misc, value); } } + public string Description { get => _description; protected set { this.RaiseAndSetIfChanged(ref _description, value); } } + public string ProductRating { get => _productRating; protected set { this.RaiseAndSetIfChanged(ref _productRating, value); } } + public string MyRating { get => _myRating; protected set { this.RaiseAndSetIfChanged(ref _myRating, value); } } + + protected bool? _remove = false; public abstract bool? Remove { get; set; } - public abstract LiberateButtonStatus2 Liberate { get; } - public Avalonia.Media.Imaging.Bitmap Cover - { - get => _cover; - protected set - { - _cover = value; - NotifyPropertyChanged(); - } - } - public string PurchaseDate { get; protected set; } - public string Series { get; protected set; } - public string Title { get; protected set; } - public string Length { get; protected set; } - public string Authors { get; set; } - public string Narrators { get; protected set; } - public string Category { get; protected set; } - public string Misc { get; protected set; } - public string Description { get; protected set; } - public string ProductRating { get; protected set; } - public string MyRating { get; protected set; } public abstract BookTags BookTags { get; } #endregion @@ -87,7 +92,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels #region Cover Art - private Avalonia.Media.Imaging.Bitmap _cover; protected void LoadCover() { // Get cover art. If it's default, subscribe to PictureCached diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/LiberateButtonStatus2.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/LiberateButtonStatus2.cs index 5d044633..f17c519c 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/LiberateButtonStatus2.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/LiberateButtonStatus2.cs @@ -1,13 +1,12 @@ using Avalonia.Media.Imaging; using DataLayer; +using ReactiveUI; using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.CompilerServices; namespace LibationWinForms.AvaloniaUI.ViewModels { - public class LiberateButtonStatus2 : IComparable, INotifyPropertyChanged + public class LiberateButtonStatus2 : ViewModelBase, IComparable { public LiberatedStatus BookStatus { get; set; } public LiberatedStatus? PdfStatus { get; set; } @@ -18,10 +17,9 @@ namespace LibationWinForms.AvaloniaUI.ViewModels get => _expanded; set { - _expanded = value; - NotifyPropertyChanged(); - NotifyPropertyChanged(nameof(Image)); - NotifyPropertyChanged(nameof(ToolTip)); + this.RaiseAndSetIfChanged(ref _expanded, value); + this.RaisePropertyChanged(nameof(Image)); + this.RaisePropertyChanged(nameof(ToolTip)); } } public bool IsSeries { get; init; } @@ -30,13 +28,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels static Dictionary images = new(); - public event PropertyChangedEventHandler PropertyChanged; - - public void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - - /// - /// Defines the Liberate column's sorting behavior - /// + /// Defines the Liberate column's sorting behavior public int CompareTo(object obj) { if (obj is not LiberateButtonStatus2 second) return -1; @@ -49,14 +41,13 @@ namespace LibationWinForms.AvaloniaUI.ViewModels else return BookStatus.CompareTo(second.BookStatus); } - private Bitmap GetLiberateIcon() { if (IsSeries) - return Expanded ? GetFromresc("minus") : GetFromresc("plus"); + return Expanded ? GetFromResources("minus") : GetFromResources("plus"); if (BookStatus == LiberatedStatus.Error) - return GetFromresc("error"); + return GetFromResources("error"); string image_lib = BookStatus switch { @@ -75,7 +66,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels _ => throw new Exception("Unexpected PDF state") }; - return GetFromresc($"liberate_{image_lib}{image_pdf}"); + return GetFromResources($"liberate_{image_lib}{image_pdf}"); } private string GetTooltip() { @@ -113,7 +104,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels return mouseoverText; } - private static Bitmap GetFromresc(string rescName) + private static Bitmap GetFromResources(string rescName) { if (images.ContainsKey(rescName)) return images[rescName]; diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/LibraryBookEntry2.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/LibraryBookEntry2.cs index be7f5cf5..7e46c741 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/LibraryBookEntry2.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/LibraryBookEntry2.cs @@ -2,6 +2,7 @@ using DataLayer; using Dinah.Core; using LibationWinForms.GridView; +using ReactiveUI; using System; using System.Collections.Generic; using System.ComponentModel; @@ -27,8 +28,9 @@ namespace LibationWinForms.AvaloniaUI.ViewModels set { _remove = value.HasValue ? value.Value : false; + Parent?.ChildRemoveUpdate(); - NotifyPropertyChanged(); + this.RaisePropertyChanged(nameof(Remove)); } } @@ -84,20 +86,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels Description = TrimTextToWord(LongDescription, 62); SeriesIndex = Book.SeriesLink.FirstOrDefault()?.Index ?? 0; - NotifyPropertyChanged(nameof(Title)); - NotifyPropertyChanged(nameof(Series)); - NotifyPropertyChanged(nameof(Length)); - NotifyPropertyChanged(nameof(MyRating)); - NotifyPropertyChanged(nameof(PurchaseDate)); - NotifyPropertyChanged(nameof(ProductRating)); - NotifyPropertyChanged(nameof(Authors)); - NotifyPropertyChanged(nameof(Narrators)); - NotifyPropertyChanged(nameof(Category)); - NotifyPropertyChanged(nameof(Misc)); - NotifyPropertyChanged(nameof(LongDescription)); - NotifyPropertyChanged(nameof(Description)); - NotifyPropertyChanged(nameof(SeriesIndex)); - UserDefinedItem.ItemChanged += UserDefinedItem_ItemChanged; } @@ -120,18 +108,18 @@ namespace LibationWinForms.AvaloniaUI.ViewModels switch (itemName) { case nameof(udi.Tags): - Book.UserDefinedItem.Tags = udi.Tags; - NotifyPropertyChanged(nameof(BookTags)); + Book.UserDefinedItem.Tags = udi.Tags; + this.RaisePropertyChanged(nameof(BookTags)); break; case nameof(udi.BookStatus): Book.UserDefinedItem.BookStatus = udi.BookStatus; _bookStatus = udi.BookStatus; - NotifyPropertyChanged(nameof(Liberate)); + this.RaisePropertyChanged(nameof(Liberate)); break; case nameof(udi.PdfStatus): Book.UserDefinedItem.PdfStatus = udi.PdfStatus; _pdfStatus = udi.PdfStatus; - NotifyPropertyChanged(nameof(Liberate)); + this.RaisePropertyChanged(nameof(Liberate)); break; } } diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBook2.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBook2.cs index 067fff42..be11604d 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBook2.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessBook2.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading.Tasks; using ApplicationServices; using Avalonia.Media.Imaging; @@ -10,6 +8,7 @@ using DataLayer; using Dinah.Core; using FileLiberator; using LibationFileManager; +using ReactiveUI; namespace LibationWinForms.AvaloniaUI.ViewModels { @@ -36,10 +35,9 @@ namespace LibationWinForms.AvaloniaUI.ViewModels /// /// This is the viewmodel for queued processables /// - public class ProcessBook2 : INotifyPropertyChanged + public class ProcessBook2 : ViewModelBase { public event EventHandler Completed; - public event PropertyChangedEventHandler PropertyChanged; public LibraryBook LibraryBook { get; private set; } @@ -53,14 +51,14 @@ namespace LibationWinForms.AvaloniaUI.ViewModels private Bitmap _cover; #region Properties exposed to the view - public ProcessBookResult Result { get => _result; set { _result = value; NotifyPropertyChanged(); NotifyPropertyChanged(nameof(StatusText)); } } - public ProcessBookStatus Status { get => _status; set { _status = value; NotifyPropertyChanged(); NotifyPropertyChanged(nameof(BackgroundColor)); NotifyPropertyChanged(nameof(IsFinished)); NotifyPropertyChanged(nameof(IsDownloading)); NotifyPropertyChanged(nameof(Queued)); } } - public string Narrator { get => _narrator; set { _narrator = value; NotifyPropertyChanged(); } } - public string Author { get => _author; set { _author = value; NotifyPropertyChanged(); } } - public string Title { get => _title; set { _title = value; NotifyPropertyChanged(); } } - public int Progress { get => _progress; private set { _progress = value; NotifyPropertyChanged(); } } - public string ETA { get => _eta; private set { _eta = value; NotifyPropertyChanged(); } } - public Bitmap Cover { get => _cover; private set { _cover = value; NotifyPropertyChanged(); } } + public ProcessBookResult Result { get => _result; set { this.RaiseAndSetIfChanged(ref _result, value); this.RaisePropertyChanged(nameof(StatusText)); } } + public ProcessBookStatus Status { get => _status; set { this.RaiseAndSetIfChanged(ref _status, value); this.RaisePropertyChanged(nameof(BackgroundColor)); this.RaisePropertyChanged(nameof(IsFinished)); this.RaisePropertyChanged(nameof(IsDownloading)); this.RaisePropertyChanged(nameof(Queued)); } } + public string Narrator { get => _narrator; set { this.RaiseAndSetIfChanged(ref _narrator, value); } } + public string Author { get => _author; set { this.RaiseAndSetIfChanged(ref _author, value); } } + public string Title { get => _title; set { this.RaiseAndSetIfChanged(ref _title, value); } } + public int Progress { get => _progress; private set { this.RaiseAndSetIfChanged(ref _progress, value); } } + public string ETA { get => _eta; private set { this.RaiseAndSetIfChanged(ref _eta, value); } } + public Bitmap Cover { get => _cover; private set { this.RaiseAndSetIfChanged(ref _cover, value); } } public bool IsFinished => Status is not ProcessBookStatus.Queued and not ProcessBookStatus.Working; public bool IsDownloading => Status is ProcessBookStatus.Working; public bool Queued => Status is ProcessBookStatus.Queued; @@ -91,8 +89,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels private Processable _currentProcessable; private readonly Queue> Processes = new(); private readonly ProcessQueue.LogMe Logger; - public void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); public ProcessBook2(LibraryBook libraryBook, ProcessQueue.LogMe logme) { diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs index 8d30937d..acde7ab6 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs @@ -7,31 +7,25 @@ namespace LibationWinForms.AvaloniaUI.ViewModels { public class ProcessQueueViewModel : ViewModelBase, ProcessQueue.ILogForm { - - public string QueueHeader => "this is a header!"; + public ObservableCollection LogEntries { get; } = new(); private TrackedQueue2 _items = new(); - public ProcessQueueViewModel() { } public TrackedQueue2 Items { get => _items; set => this.RaiseAndSetIfChanged(ref _items, value); } - - public ObservableCollection LogEntries { get; } = new(); - public ProcessBook2 SelectedItem { get; set; } public void WriteLine(string text) { Dispatcher.UIThread.Post(() => - LogEntries.Add(new() - { - LogDate = DateTime.Now, - LogMessage = text.Trim() - })); + LogEntries.Add(new() + { + LogDate = DateTime.Now, + LogMessage = text.Trim() + })); } - } public class LogEntry @@ -40,5 +34,4 @@ namespace LibationWinForms.AvaloniaUI.ViewModels public string LogDateString => LogDate.ToShortTimeString(); public string LogMessage { get; init; } } - } diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/SeriesEntrys2.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/SeriesEntrys2.cs index 3a403335..21c41bcb 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/SeriesEntrys2.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/SeriesEntrys2.cs @@ -1,6 +1,6 @@ using DataLayer; using Dinah.Core; -using LibationWinForms.GridView; +using ReactiveUI; using System; using System.Collections.Generic; using System.ComponentModel; @@ -21,13 +21,8 @@ namespace LibationWinForms.AvaloniaUI.ViewModels var removeCount = Children.Count(c => c.Remove == true); - if (removeCount == 0) - _remove = false; - else if (removeCount == Children.Count) - _remove = true; - else - _remove = null; - NotifyPropertyChanged(nameof(Remove)); + _remove = removeCount == 0 ? false : (removeCount == Children.Count ? true : null); + this.RaisePropertyChanged(nameof(Remove)); } #region Model properties exposed to the view @@ -36,7 +31,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels get => _remove; set { - _remove = value.HasValue ? value : false; + _remove = value.HasValue ? value.Value : false; suspendCounting = true; @@ -44,13 +39,12 @@ namespace LibationWinForms.AvaloniaUI.ViewModels item.Remove = value; suspendCounting = false; - - NotifyPropertyChanged(); + this.RaisePropertyChanged(nameof(Remove)); } } public override LiberateButtonStatus2 Liberate { get; } - public override BookTags BookTags { get; } = new() { IsSeries = true }; + public override BookTags BookTags { get; } = new(); #endregion @@ -95,19 +89,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels int bookLenMins = Children.Sum(c => c.LibraryBook.Book.LengthInMinutes); Length = bookLenMins == 0 ? "" : $"{bookLenMins / 60} hr {bookLenMins % 60} min"; - - NotifyPropertyChanged(nameof(Title)); - NotifyPropertyChanged(nameof(Series)); - NotifyPropertyChanged(nameof(Length)); - NotifyPropertyChanged(nameof(MyRating)); - NotifyPropertyChanged(nameof(PurchaseDate)); - NotifyPropertyChanged(nameof(ProductRating)); - NotifyPropertyChanged(nameof(Authors)); - NotifyPropertyChanged(nameof(Narrators)); - NotifyPropertyChanged(nameof(Category)); - NotifyPropertyChanged(nameof(Misc)); - NotifyPropertyChanged(nameof(LongDescription)); - NotifyPropertyChanged(nameof(Description)); } #region Data Sorting diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/ViewModelBase.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/ViewModelBase.cs index 29d0d3fc..060934f0 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/ViewModelBase.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/ViewModelBase.cs @@ -1,3 +1,4 @@ +using Avalonia.Controls; using ReactiveUI; using System; using System.Collections.Generic; @@ -7,5 +8,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels { public class ViewModelBase : ReactiveObject { + } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml b/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml index 15f17211..55a4323f 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml @@ -11,7 +11,7 @@ - + @@ -147,7 +147,7 @@ -