diff --git a/LibationWinForms/AsyncNotifyPropertyChanged.cs b/LibationWinForms/AsyncNotifyPropertyChanged.cs index 20b8b512..96f007ed 100644 --- a/LibationWinForms/AsyncNotifyPropertyChanged.cs +++ b/LibationWinForms/AsyncNotifyPropertyChanged.cs @@ -1,6 +1,6 @@ -using System.ComponentModel; +using Dinah.Core.Threading; +using System.ComponentModel; using System.Runtime.CompilerServices; -using System.Threading; namespace LibationWinForms { @@ -8,9 +8,7 @@ namespace LibationWinForms { public event PropertyChangedEventHandler PropertyChanged; - public AsyncNotifyPropertyChanged() { } - protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - =>BeginInvoke(PropertyChanged, new object[] { this, new PropertyChangedEventArgs(propertyName) }); + => this.UIThread(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName))); } } diff --git a/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs b/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs index b69fa90d..dbf80104 100644 --- a/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs +++ b/LibationWinForms/BookLiberation/BaseForms/LiberationBaseForm.cs @@ -1,6 +1,6 @@ using DataLayer; using Dinah.Core.Net.Http; -using Dinah.Core.Windows.Forms; +using Dinah.Core.Threading; using FileLiberator; using System; using System.Windows.Forms; @@ -122,8 +122,8 @@ namespace LibationWinForms.BookLiberation.BaseForms /// /// If the form was shown using Show (not ShowDialog), Form.Close calls Form.Dispose /// - private void OnStreamingCompletedClose(object sender, string completedString) => this.UIThread(() => Close()); - private void OnCompletedDispose(object sender, LibraryBook e) => this.UIThread(() => Dispose()); + private void OnStreamingCompletedClose(object sender, string completedString) => this.UIThread(Close); + private void OnCompletedDispose(object sender, LibraryBook e) => this.UIThread(Dispose); /// /// If StreamingBegin is fired from a worker thread, the window will be created on that @@ -132,7 +132,7 @@ namespace LibationWinForms.BookLiberation.BaseForms /// could cause it to freeze. Form.BeginInvoke won't work until the form is created /// (ie. shown) because Control doesn't get a window handle until it is Shown. /// - private void OnStreamingBeginShow(object sender, string beginString) => Invoker.Invoke(Show); + private void OnStreamingBeginShow(object sender, string beginString) => Invoker.UIThread(Show); #endregion diff --git a/LibationWinForms/DataGridViewImageButtonCell.cs b/LibationWinForms/DataGridViewImageButtonCell.cs new file mode 100644 index 00000000..f4f25afd --- /dev/null +++ b/LibationWinForms/DataGridViewImageButtonCell.cs @@ -0,0 +1,18 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace LibationWinForms +{ + public class DataGridViewImageButtonCell : DataGridViewButtonCell + { + protected void DrawButtonImage(Graphics graphics, Image image, Rectangle cellBounds) + { + var w = image.Width; + var h = image.Height; + var x = cellBounds.Left + (cellBounds.Width - w) / 2; + var y = cellBounds.Top + (cellBounds.Height - h) / 2; + + graphics.DrawImage(image, new Rectangle(x, y, w, h)); + } + } +} diff --git a/LibationWinForms/DataGridViewImageButtonColumn.cs b/LibationWinForms/DataGridViewImageButtonColumn.cs deleted file mode 100644 index e607a069..00000000 --- a/LibationWinForms/DataGridViewImageButtonColumn.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Drawing; -using System.Windows.Forms; - -namespace LibationWinForms -{ - public abstract class DataGridViewImageButtonColumn : DataGridViewButtonColumn - { - private DataGridViewImageButtonCell _cellTemplate; - public override DataGridViewCell CellTemplate - { - get => GetCellTemplate(); - set - { - if (value is DataGridViewImageButtonCell cellTemplate) - _cellTemplate = cellTemplate; - } - } - - protected abstract DataGridViewImageButtonCell NewCell(); - - private DataGridViewImageButtonCell GetCellTemplate() - { - if (_cellTemplate is null) - return NewCell(); - else - return _cellTemplate; - } - - public override object Clone() - { - var clone = (DataGridViewImageButtonColumn)base.Clone(); - clone._cellTemplate = _cellTemplate; - - return clone; - } - } - - public class DataGridViewImageButtonCell : DataGridViewButtonCell - { - protected void DrawButtonImage(Graphics graphics, Image image, Rectangle cellBounds) - { - var w = image.Width; - var h = image.Height; - var x = cellBounds.Left + (cellBounds.Width - w) / 2; - var y = cellBounds.Top + (cellBounds.Height - h) / 2; - - graphics.DrawImage(image, new Rectangle(x, y, w, h)); - } - } -} diff --git a/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs b/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs index e736b938..d76cc04a 100644 --- a/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs +++ b/LibationWinForms/EditTagsDataGridViewImageButtonColumn.cs @@ -3,10 +3,12 @@ using System.Windows.Forms; namespace LibationWinForms { - public class EditTagsDataGridViewImageButtonColumn : DataGridViewImageButtonColumn + public class EditTagsDataGridViewImageButtonColumn : DataGridViewButtonColumn { - protected override DataGridViewImageButtonCell NewCell() - => new EditTagsDataGridViewImageButtonCell(); + public EditTagsDataGridViewImageButtonColumn() + { + CellTemplate = new EditTagsDataGridViewImageButtonCell(); + } } internal class EditTagsDataGridViewImageButtonCell : DataGridViewImageButtonCell diff --git a/LibationWinForms/GridEntry.cs b/LibationWinForms/GridEntry.cs index d66b8a73..857469c6 100644 --- a/LibationWinForms/GridEntry.cs +++ b/LibationWinForms/GridEntry.cs @@ -7,6 +7,7 @@ using System.Linq; using ApplicationServices; using DataLayer; using Dinah.Core.DataBinding; +using Dinah.Core; using Dinah.Core.Drawing; namespace LibationWinForms @@ -47,9 +48,9 @@ namespace LibationWinForms Title = Book.Title; Series = Book.SeriesNames; Length = Book.LengthInMinutes == 0 ? "" : $"{Book.LengthInMinutes / 60} hr {Book.LengthInMinutes % 60} min"; - MyRating = ValueOrDefault(Book.UserDefinedItem.Rating?.ToStarString(), ""); + MyRating = Book.UserDefinedItem.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); PurchaseDate = libraryBook.DateAdded.ToString("d"); - ProductRating = ValueOrDefault(Book.Rating?.ToStarString(), ""); + ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace(""); Authors = Book.AuthorNames; Narrators = Book.NarratorNames; Category = string.Join(" > ", Book.CategoriesNames); @@ -207,8 +208,8 @@ namespace LibationWinForms { var details = new List(); - var locale = ValueOrDefault(libraryBook.Book.Locale, "[unknown]"); - var acct = ValueOrDefault(libraryBook.Account, "[unknown]"); + var locale = libraryBook.Book.Locale.DefaultIfNullOrWhiteSpace("[unknown]"); + var acct = libraryBook.Account.DefaultIfNullOrWhiteSpace("[unknown]"); details.Add($"Account: {locale} - {acct}"); @@ -228,10 +229,6 @@ namespace LibationWinForms return string.Join("\r\n", details); } - //Maybe add to Dinah StringExtensions? - private static string ValueOrDefault(string value, string defaultValue) - => string.IsNullOrWhiteSpace(value) ? defaultValue : value; - #endregion } } diff --git a/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs b/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs index 4802fa96..6427677c 100644 --- a/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs +++ b/LibationWinForms/LiberateDataGridViewImageButtonColumn.cs @@ -6,10 +6,12 @@ using System.Linq; namespace LibationWinForms { - public class LiberateDataGridViewImageButtonColumn : DataGridViewImageButtonColumn + public class LiberateDataGridViewImageButtonColumn : DataGridViewButtonColumn { - protected override DataGridViewImageButtonCell NewCell() - => new LiberateDataGridViewImageButtonCell(); + public LiberateDataGridViewImageButtonColumn() + { + CellTemplate = new LiberateDataGridViewImageButtonCell(); + } } internal class LiberateDataGridViewImageButtonCell : DataGridViewImageButtonCell diff --git a/LibationWinForms/ProductsGrid.Designer.cs b/LibationWinForms/ProductsGrid.Designer.cs index 529a7783..82f5703e 100644 --- a/LibationWinForms/ProductsGrid.Designer.cs +++ b/LibationWinForms/ProductsGrid.Designer.cs @@ -92,7 +92,7 @@ this.gridEntryDataGridView.ReadOnly = true; this.gridEntryDataGridView.RowHeadersVisible = false; this.gridEntryDataGridView.RowTemplate.Height = 82; - this.gridEntryDataGridView.Size = new System.Drawing.Size(1505, 380); + this.gridEntryDataGridView.Size = new System.Drawing.Size(1510, 380); this.gridEntryDataGridView.TabIndex = 0; // // dataGridViewImageButtonBoxColumn1 @@ -103,7 +103,7 @@ this.dataGridViewImageButtonBoxColumn1.ReadOnly = true; this.dataGridViewImageButtonBoxColumn1.Resizable = System.Windows.Forms.DataGridViewTriState.False; this.dataGridViewImageButtonBoxColumn1.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; - this.dataGridViewImageButtonBoxColumn1.Width = 70; + this.dataGridViewImageButtonBoxColumn1.Width = 75; // // dataGridViewImageColumn1 // @@ -213,7 +213,7 @@ this.Controls.Add(this.gridEntryDataGridView); this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); this.Name = "ProductsGrid"; - this.Size = new System.Drawing.Size(1505, 380); + this.Size = new System.Drawing.Size(1510, 380); ((System.ComponentModel.ISupportInitialize)(this.gridEntryBindingSource)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.gridEntryDataGridView)).EndInit(); this.ResumeLayout(false); diff --git a/LibationWinForms/SynchronizeInvoker.cs b/LibationWinForms/SynchronizeInvoker.cs deleted file mode 100644 index c38c0499..00000000 --- a/LibationWinForms/SynchronizeInvoker.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.ComponentModel; -using System.Threading; - -namespace LibationWinForms -{ - public class SynchronizeInvoker : ISynchronizeInvoke - { - public bool InvokeRequired => Thread.CurrentThread.ManagedThreadId != InstanceThreadId; - private int InstanceThreadId { get; set; } = Thread.CurrentThread.ManagedThreadId; - private SynchronizationContext SyncContext { get; } = SynchronizationContext.Current; - - public SynchronizeInvoker() - { - if (SyncContext is null) - throw new NullReferenceException($"Could not capture a current {nameof(SynchronizationContext)}"); - } - - public IAsyncResult BeginInvoke(Action action) => BeginInvoke(action, null); - public IAsyncResult BeginInvoke(Delegate method) => BeginInvoke(method, null); - public IAsyncResult BeginInvoke(Delegate method, object[] args) - { - var tme = new ThreadMethodEntry(method, args); - - if (InvokeRequired) - { - SyncContext.Post(OnSendOrPostCallback, tme); - } - else - { - tme.Complete(); - tme.CompletedSynchronously = true; - } - return tme; - } - - public object EndInvoke(IAsyncResult result) - { - if (result is not ThreadMethodEntry crossThread) - throw new ArgumentException($"{nameof(result)} was not returned by {nameof(SynchronizeInvoker)}.{nameof(BeginInvoke)}"); - - if (!crossThread.IsCompleted) - crossThread.AsyncWaitHandle.WaitOne(); - - return crossThread.ReturnValue; - } - - public object Invoke(Action action) => Invoke(action, null); - public object Invoke(Delegate method) => Invoke(method, null); - public object Invoke(Delegate method, object[] args) - { - var tme = new ThreadMethodEntry(method, args); - - if (InvokeRequired) - { - SyncContext.Send(OnSendOrPostCallback, tme); - } - else - { - tme.Complete(); - tme.CompletedSynchronously = true; - } - - return tme.ReturnValue; - } - - /// - /// This callback executes on the SynchronizationContext thread. - /// - private static void OnSendOrPostCallback(object asyncArgs) - { - var e = asyncArgs as ThreadMethodEntry; - e.Complete(); - } - - private class ThreadMethodEntry : IAsyncResult - { - public object AsyncState => null; - public bool CompletedSynchronously { get; internal set; } - public bool IsCompleted { get; private set; } - public object ReturnValue { get; private set; } - public WaitHandle AsyncWaitHandle => completedEvent; - - private Delegate method; - private object[] args; - private ManualResetEvent completedEvent; - - public ThreadMethodEntry(Delegate method, object[] args) - { - this.method = method; - this.args = args; - completedEvent = new ManualResetEvent(initialState: false); - } - - public void Complete() - { - try - { - switch (method) - { - case Action actiton: - actiton(); - break; - default: - ReturnValue = method.DynamicInvoke(args); - break; - } - } - finally - { - IsCompleted = true; - completedEvent.Set(); - } - } - - ~ThreadMethodEntry() - { - completedEvent.Close(); - } - } - } -} \ No newline at end of file