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
{
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.
//protected abstract bool HasIdValue(TDataItem dataItem);
//protected abstract int FindIndex(TDataItem newValue);
//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();
public int FindIndex(TDataItem newValue) => _trackingItems.FindIndex(x => _equalityComparer.Equals(x.CurrentValue.Id, newValue.Id));
private bool HasIdValue(TDataItem dataItem) => !_equalityComparerId.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty();
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)
{
trackingItem = _trackingItems.FirstOrDefault(x => _equalityComparer.Equals(x.CurrentValue.Id, id));
trackingItem = _trackingItems.FirstOrDefault(x => _equalityComparerId.Equals(x.CurrentValue.Id, id));
return trackingItem != null;
}
@ -165,7 +165,7 @@ namespace AyCode.Services.Server.SignalRs
where TIList : class, IList<TDataItem>
{
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 readonly ChangeTracking<TDataItem, TId> TrackingItems = new();
@ -184,8 +184,8 @@ namespace AyCode.Services.Server.SignalRs
//protected abstract int FindIndexInnerList(TId id);
//protected abstract TDataItem? FirstOrDefaultInnerList(TId id);
protected bool HasIdValue(TDataItem dataItem) => !_equalityComparer.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty();
protected bool IdEquals(TId id1, TId id2) => _equalityComparer.Equals(id1, id2);
protected bool HasIdValue(TDataItem dataItem) => !_equalityComparerId.Equals(dataItem.Id, default);//dataItem.Id.IsNullOrEmpty();
protected bool IdEquals(TId id1, TId id2) => _equalityComparerId.Equals(id1, id2);
protected int FindIndexInnerList(TId id) => InnerList.FindIndex(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)
{
if (destination is List<TDataItem> dest) dest.AddRange(source);
else
switch (destination)
{
foreach (var dataItem in source)
destination.Add(dataItem);
case IAcFastObservableCollection dest:
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)
{
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);
@ -854,7 +863,7 @@ namespace AyCode.Services.Server.SignalRs
throw new NullReferenceException($"SaveItemUnsafe; result == null");
}
ProcessSavedResponseItem(x.Result, trackingState);
ProcessSavedResponseItem(x.Result, trackingState, item.Id);
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}");
}
return ProcessSavedResponseItem(response.ResponseData, trackingState);
return ProcessSavedResponseItem(response.ResponseData, trackingState, item.Id);
}
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 (TryGetTrackingItem(resultItem.Id, out var trackingItem))
if (TryGetTrackingItem(originalId, out var trackingItem))
TrackingItems.Remove(trackingItem);
if (TryGetIndex(resultItem.Id, out var index))
if (TryGetIndex(originalId, out var index))
InnerList[index] = resultItem;
var eventArgs = new ItemChangedEventArgs<TDataItem>(resultItem, trackingState);

View File

@ -207,7 +207,7 @@ public abstract class AcWebSignalRHubBase<TSignalRTags, TLogger>(IConfiguration
if (Context.User != null)
{
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}");