improvements, fixes

This commit is contained in:
Loretta 2025-11-20 08:30:37 +01:00
parent dd5dc68862
commit e0666027b3
3 changed files with 179 additions and 18 deletions

View File

@ -0,0 +1,152 @@
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
namespace AyCode.Core.Helpers
{
public interface IAcFastObservableCollection
{
public void AddRange(IEnumerable other);
public void Replace(IEnumerable other);
public void RemoveRange(IEnumerable other);
public void Synchronize(NotifyCollectionChangedEventArgs args);
}
public interface IAcFastObservableCollection<T> : IAcFastObservableCollection
{
public void Replace(IEnumerable<T> other);
public void Sort(IComparer<T> comparer);
public void SortAndReplace(IEnumerable<T> other, IComparer<T> comparer);
}
public class AcFastObservableCollection<T> : ObservableCollection<T>, IAcFastObservableCollection<T>
{
private bool _suppressChangedEvent;
public void Replace(IEnumerable<T> other)
{
_suppressChangedEvent = true;
Clear();
AddRange(other);
}
public void Replace(IEnumerable other)
{
_suppressChangedEvent = true;
Clear();
foreach (T item in other) Add(item);
_suppressChangedEvent = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
}
public void AddRange(IEnumerable other)
{
_suppressChangedEvent = true;
foreach (var item in other)
{
if (item is T tItem) Add(tItem);
}
_suppressChangedEvent = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
}
public void RemoveRange(IEnumerable other)
{
_suppressChangedEvent = true;
foreach (var item in other)
{
if (item is T tItem) Remove(tItem);
}
_suppressChangedEvent = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));
}
public void SortAndReplace(IEnumerable<T> other, IComparer<T> comparer)
{
List<T> values = new(other);
values.Sort(comparer);
Replace(values);
}
public void Sort(IComparer<T> comparer)
{
List<T> values = new(this);
values.Sort(comparer);
Replace(values);
}
public void Synchronize(NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add when args.NewItems != null:
AddRange(args.NewItems);
break;
case NotifyCollectionChangedAction.Remove when args.OldItems != null:
RemoveRange(args.OldItems);
break;
case NotifyCollectionChangedAction.Reset:
Clear();
break;
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (_suppressChangedEvent)
return;
base.OnPropertyChanged(e);
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (_suppressChangedEvent)
return;
base.OnCollectionChanged(e);
}
//protected override void ClearItems()
//{
// base.ClearItems();
//}
//protected override void InsertItem(int index, T item)
//{
// base.InsertItem(index, item);
//}
//protected override void MoveItem(int oldIndex, int newIndex)
//{
// base.MoveItem(oldIndex, newIndex);
//}
//public override event NotifyCollectionChangedEventHandler? CollectionChanged
//{
// add => base.CollectionChanged += value;
// remove => base.CollectionChanged -= value;
//}
}
}

View File

@ -61,18 +61,18 @@ namespace AyCode.Services.Server.SignalRs
public class ChangeTracking<TDataItem, TId> /*: IEnumerable<TrackingItem<T>>*/where TDataItem : class, IId<TId> where TId : struct public class ChangeTracking<TDataItem, TId> /*: IEnumerable<TrackingItem<T>>*/where TDataItem : class, IId<TId> where TId : struct
{ {
private readonly EqualityComparer<TId> _equalityComparer = EqualityComparer<TId>.Default; private readonly EqualityComparer<TId> _equalityComparerId = EqualityComparer<TId>.Default;
private readonly List<TrackingItem<TDataItem, TId>> _trackingItems = []; //TODO: Dictionary... - J. private readonly List<TrackingItem<TDataItem, TId>> _trackingItems = []; //TODO: Dictionary... - J.
//protected abstract bool HasIdValue(TDataItem dataItem); //protected abstract bool HasIdValue(TDataItem dataItem);
//protected abstract int FindIndex(TDataItem newValue); //protected abstract int FindIndex(TDataItem newValue);
//public abstract bool TryGetTrackingItem(TId id, [NotNullWhen(true)] out TrackingItem<TDataItem, TId>? trackingItem); //public abstract bool TryGetTrackingItem(TId id, [NotNullWhen(true)] out TrackingItem<TDataItem, TId>? trackingItem);
private bool HasIdValue(TDataItem dataItem) => !_equalityComparer.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty(); private bool HasIdValue(TDataItem dataItem) => !_equalityComparerId.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty();
public int FindIndex(TDataItem newValue) => _trackingItems.FindIndex(x => _equalityComparer.Equals(x.CurrentValue.Id, newValue.Id)); public int FindIndex(TDataItem newValue) => _trackingItems.FindIndex(x => _equalityComparerId.Equals(x.CurrentValue.Id, newValue.Id));
public bool TryGetTrackingItem(TId id, [NotNullWhen(true)] out TrackingItem<TDataItem, TId>? trackingItem) public bool TryGetTrackingItem(TId id, [NotNullWhen(true)] out TrackingItem<TDataItem, TId>? trackingItem)
{ {
trackingItem = _trackingItems.FirstOrDefault(x => _equalityComparer.Equals(x.CurrentValue.Id, id)); trackingItem = _trackingItems.FirstOrDefault(x => _equalityComparerId.Equals(x.CurrentValue.Id, id));
return trackingItem != null; return trackingItem != null;
} }
@ -165,7 +165,7 @@ namespace AyCode.Services.Server.SignalRs
where TIList : class, IList<TDataItem> where TIList : class, IList<TDataItem>
{ {
private readonly object _syncRoot = new(); private readonly object _syncRoot = new();
private readonly EqualityComparer<TId> _equalityComparer = EqualityComparer<TId>.Default; private readonly EqualityComparer<TId> _equalityComparerId = EqualityComparer<TId>.Default;
protected TIList InnerList = Activator.CreateInstance<TIList>();// []; //TODO: Dictionary??? - J. protected TIList InnerList = Activator.CreateInstance<TIList>();// []; //TODO: Dictionary??? - J.
protected readonly ChangeTracking<TDataItem, TId> TrackingItems = new(); protected readonly ChangeTracking<TDataItem, TId> TrackingItems = new();
@ -184,8 +184,8 @@ namespace AyCode.Services.Server.SignalRs
//protected abstract int FindIndexInnerList(TId id); //protected abstract int FindIndexInnerList(TId id);
//protected abstract TDataItem? FirstOrDefaultInnerList(TId id); //protected abstract TDataItem? FirstOrDefaultInnerList(TId id);
protected bool HasIdValue(TDataItem dataItem) => !_equalityComparer.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty(); protected bool HasIdValue(TDataItem dataItem) => !_equalityComparerId.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty();
protected bool IdEquals(TId id1, TId id2) => _equalityComparer.Equals(id1, id2); protected bool IdEquals(TId id1, TId id2) => _equalityComparerId.Equals(id1, id2);
protected int FindIndexInnerList(TId id) => InnerList.FindIndex(x => IdEquals(x.Id, id)); protected int FindIndexInnerList(TId id) => InnerList.FindIndex(x => IdEquals(x.Id, id));
protected TDataItem? FirstOrDefaultInnerList(TId id) => InnerList.FirstOrDefault(x => IdEquals(x.Id, id)); protected TDataItem? FirstOrDefaultInnerList(TId id) => InnerList.FirstOrDefault(x => IdEquals(x.Id, id));
@ -265,11 +265,20 @@ namespace AyCode.Services.Server.SignalRs
protected void AddRange(IEnumerable<TDataItem> source, TIList destination) protected void AddRange(IEnumerable<TDataItem> source, TIList destination)
{ {
if (destination is List<TDataItem> dest) dest.AddRange(source); switch (destination)
else
{ {
foreach (var dataItem in source) case IAcFastObservableCollection dest:
destination.Add(dataItem); dest.AddRange(source);
break;
case List<TDataItem> dest:
dest.AddRange(source);
break;
default:
{
foreach (var dataItem in source)
destination.Add(dataItem);
break;
}
} }
} }
@ -371,7 +380,7 @@ namespace AyCode.Services.Server.SignalRs
public void Add(TDataItem newValue) public void Add(TDataItem newValue)
{ {
if (!HasIdValue(newValue)) throw new ArgumentNullException(nameof(newValue), @"Add->newValue.Id.IsNullOrEmpty()"); if (!HasIdValue(newValue)) throw new ArgumentNullException(nameof(newValue), @"Add->HasIdValue(newValue) == false");
Monitor.Enter(_syncRoot); Monitor.Enter(_syncRoot);
@ -854,7 +863,7 @@ namespace AyCode.Services.Server.SignalRs
throw new NullReferenceException($"SaveItemUnsafe; result == null"); throw new NullReferenceException($"SaveItemUnsafe; result == null");
} }
ProcessSavedResponseItem(x.Result, trackingState); ProcessSavedResponseItem(x.Result, trackingState, item.Id);
return x.Result; return x.Result;
}); });
} }
@ -877,7 +886,7 @@ namespace AyCode.Services.Server.SignalRs
throw new NullReferenceException($"SaveItemUnsafeAsync; result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}"); throw new NullReferenceException($"SaveItemUnsafeAsync; result.Status != SignalResponseStatus.Success || result.ResponseData == null; Status: {SignalResponseStatus.Success}");
} }
return ProcessSavedResponseItem(response.ResponseData, trackingState); return ProcessSavedResponseItem(response.ResponseData, trackingState, item.Id);
} }
finally finally
{ {
@ -886,14 +895,14 @@ namespace AyCode.Services.Server.SignalRs
}); });
} }
private Task ProcessSavedResponseItem(TDataItem? resultItem, TrackingState trackingState) private Task ProcessSavedResponseItem(TDataItem? resultItem, TrackingState trackingState, TId originalId)
{ {
if (resultItem == null) return Task.CompletedTask; if (resultItem == null) return Task.CompletedTask;
if (TryGetTrackingItem(resultItem.Id, out var trackingItem)) if (TryGetTrackingItem(originalId, out var trackingItem))
TrackingItems.Remove(trackingItem); TrackingItems.Remove(trackingItem);
if (TryGetIndex(resultItem.Id, out var index)) if (TryGetIndex(originalId, out var index))
InnerList[index] = resultItem; InnerList[index] = resultItem;
var eventArgs = new ItemChangedEventArgs<TDataItem>(resultItem, trackingState); var eventArgs = new ItemChangedEventArgs<TDataItem>(resultItem, trackingState);

View File

@ -207,7 +207,7 @@ public abstract class AcWebSignalRHubBase<TSignalRTags, TLogger>(IConfiguration
if (Context.User != null) if (Context.User != null)
{ {
userName = Context.User.Identity?.Name; userName = Context.User.Identity?.Name;
Guid.TryParse((string?)Context.User.FindFirstValue(ClaimTypes.NameIdentifier), out userId); Guid.TryParse(Context.User.FindFirstValue(ClaimTypes.NameIdentifier), out userId);
} }
if (AcDomain.IsDeveloperVersion) Logger.WarningConditional($"SignalR.Context; userName: {userName}; userId: {userId}"); if (AcDomain.IsDeveloperVersion) Logger.WarningConditional($"SignalR.Context; userName: {userName}; userId: {userId}");