committed by
GitHub
71 changed files with 759 additions and 391 deletions
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Avalonia.Diagnostics.ViewModels |
||||
|
{ |
||||
|
public class ViewModelBase : INotifyPropertyChanged |
||||
|
{ |
||||
|
public event PropertyChangedEventHandler PropertyChanged; |
||||
|
|
||||
|
[NotifyPropertyChangedInvocator] |
||||
|
protected bool RaiseAndSetIfChanged<T>(ref T field, T value, [CallerMemberName] string propertyName = null) |
||||
|
{ |
||||
|
if (!EqualityComparer<T>.Default.Equals(field, value)) |
||||
|
{ |
||||
|
field = value; |
||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
[NotifyPropertyChangedInvocator] |
||||
|
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) |
||||
|
{ |
||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel; |
||||
|
using System.Reactive.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
namespace Avalonia.Diagnostics.Views |
||||
|
{ |
||||
|
internal static class PropertyChangedExtenions |
||||
|
{ |
||||
|
public static IObservable<T> GetObservable<T>(this INotifyPropertyChanged source, string propertyName) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(source != null); |
||||
|
Contract.Requires<ArgumentNullException>(propertyName != null); |
||||
|
|
||||
|
var property = source.GetType().GetTypeInfo().GetDeclaredProperty(propertyName); |
||||
|
|
||||
|
if (property == null) |
||||
|
{ |
||||
|
throw new ArgumentException($"Property '{propertyName}' not found on '{source}."); |
||||
|
} |
||||
|
|
||||
|
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>( |
||||
|
e => source.PropertyChanged += e, |
||||
|
e => source.PropertyChanged -= e) |
||||
|
.Where(e => e.EventArgs.PropertyName == propertyName) |
||||
|
.Select(_ => (T)property.GetValue(source)) |
||||
|
.StartWith((T)property.GetValue(source)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,134 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Collections; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Base.UnitTests.Collections |
||||
|
{ |
||||
|
public class AvaloniaListExtenionsTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Creates_Initial_Items() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_Add() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source.Add(4); |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_Insert() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source.Insert(1, 4); |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_Remove() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source.Remove(2); |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_RemoveRange() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source.RemoveRange(1, 2); |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_Move() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source.Move(2, 0); |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_MoveRange() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source.MoveRange(1, 2, 0); |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_Replace() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source[1] = 4; |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CreateDerivedList_Handles_Clear() |
||||
|
{ |
||||
|
var source = new AvaloniaList<int>(new[] { 0, 1, 2, 3 }); |
||||
|
var target = source.CreateDerivedList(x => new Wrapper(x)); |
||||
|
|
||||
|
source.Clear(); |
||||
|
|
||||
|
var result = target.Select(x => x.Value).ToList(); |
||||
|
|
||||
|
Assert.Equal(source, result); |
||||
|
} |
||||
|
|
||||
|
private class Wrapper |
||||
|
{ |
||||
|
public Wrapper(int value) |
||||
|
{ |
||||
|
Value = value; |
||||
|
} |
||||
|
|
||||
|
public int Value { get; } |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue