A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

87 lines
3.1 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Utilities;
namespace Avalonia.Data.Core
{
public abstract class IndexerNodeBase : SettableNode
{
private IDisposable? _subscription;
protected override void StartListeningCore(WeakReference<object?> reference)
{
reference.TryGetTarget(out var target);
var incc = target as INotifyCollectionChanged;
var inpc = target as INotifyPropertyChanged;
var inputs = new List<IObservable<object?>>();
if (incc != null)
{
inputs.Add(WeakObservable.FromEventPattern(
incc, WeakEvents.CollectionChanged)
.Where(x => ShouldUpdate(x.Sender, x.EventArgs))
.Select(_ => GetValue(target)));
}
if (inpc != null)
{
inputs.Add(WeakObservable.FromEventPattern(
inpc, WeakEvents.PropertyChanged)
.Where(x => ShouldUpdate(x.Sender, x.EventArgs))
.Select(_ => GetValue(target)));
}
_subscription = Observable.Merge(inputs).StartWith(GetValue(target)).Subscribe(ValueChanged);
}
protected override void StopListeningCore()
{
_subscription?.Dispose();
}
protected abstract object? GetValue(object? target);
protected abstract int? TryGetFirstArgumentAsInt();
private bool ShouldUpdate(object? sender, NotifyCollectionChangedEventArgs e)
{
if (sender is IList)
{
var index = TryGetFirstArgumentAsInt();
if (index == null)
{
return false;
}
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
return index >= e.NewStartingIndex;
case NotifyCollectionChangedAction.Remove:
return index >= e.OldStartingIndex;
case NotifyCollectionChangedAction.Replace:
return index >= e.NewStartingIndex &&
index < e.NewStartingIndex + e.NewItems!.Count;
case NotifyCollectionChangedAction.Move:
return (index >= e.NewStartingIndex &&
index < e.NewStartingIndex + e.NewItems!.Count) ||
(index >= e.OldStartingIndex &&
index < e.OldStartingIndex + e.OldItems!.Count);
case NotifyCollectionChangedAction.Reset:
return true;
}
}
return true; // Implementation defined meaning for the index, so just try to update anyway
}
protected abstract bool ShouldUpdate(object? sender, PropertyChangedEventArgs e);
}
}