improvements, fixes
This commit is contained in:
parent
dd5dc68862
commit
e0666027b3
|
|
@ -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;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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}");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue