Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge remote-tracking branch 'origin/rxui5-master' into portable

  • Loading branch information...
commit 5c8a45deca080dde5afc0e9d0b3d830a2eb40784 2 parents c5acf5b + bad6143
@paulcbetts paulcbetts authored
View
2  ReactiveUI.Routing/RoutedViewHost.cs
@@ -52,6 +52,8 @@ public RoutedViewHost()
HorizontalContentAlignment = HorizontalAlignment.Stretch;
VerticalContentAlignment = VerticalAlignment.Stretch;
+ if (RxApp.InUnitTestRunner()) return;
+
this.WhenAny(x => x.Router.NavigationStack, x => x.Value)
.SelectMany(x => x.CollectionCountChanged.StartWith(x.Count).Select(_ => x.LastOrDefault()))
.Subscribe(vm => {
View
96 ReactiveUI.Tests/OrderedComparerTests.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace ReactiveUI.Tests
+{
+ public class OrderedComparerTests
+ {
+ [DebuggerDisplay("{Name}")]
+ public class Employee
+ {
+ public string Name;
+ public int Age;
+ public int Salary;
+ }
+
+ [Fact]
+ public void SmokeTest()
+ {
+ var adam = new Employee { Name = "Adam", Age = 50, Salary = 125 };
+ var alice = new Employee { Name = "Alice", Age = 25, Salary = 100 };
+ var bob = new Employee { Name = "Bob", Age = 30, Salary = 75 };
+ var carol = new Employee { Name = "Carol", Age = 35, Salary = 100 };
+ var xavier = new Employee { Name = "Xavier", Age = 35, Salary = 100 };
+
+ var employees = new List<Employee> { adam, alice, bob, carol, xavier };
+
+ employees.Sort(OrderedComparer<Employee>.OrderBy(x => x.Name));
+ Assert.True(employees.SequenceEqual(new[] { adam, alice, bob, carol, xavier }));
+
+ employees.Sort(OrderedComparer<Employee>
+ .OrderByDescending(x => x.Age)
+ .ThenBy(x => x.Name)
+ );
+ Assert.True(employees.SequenceEqual(new[] { adam, carol, xavier, bob, alice }));
+
+ employees.Sort(OrderedComparer<Employee>
+ .OrderByDescending(x => x.Salary)
+ .ThenBy(x => x.Name, StringComparer.OrdinalIgnoreCase)
+ );
+ Assert.True(employees.SequenceEqual(new[] { adam, alice, carol, xavier, bob }));
+
+ employees.Sort(OrderedComparer<Employee>
+ .OrderByDescending(x => x.Age)
+ .ThenByDescending(x => x.Salary)
+ .ThenBy(x => x.Name)
+ );
+ Assert.True(employees.SequenceEqual(new[] { adam, carol, xavier, bob, alice }));
+ }
+
+ [Fact]
+ public void CustomComparerTest()
+ {
+ var items = new List<string> { "aaa", "AAA", "abb", "aaaa" };
+
+ items.Sort(OrderedComparer<string>.OrderBy(x => x, StringComparer.Ordinal));
+ Assert.True(items.SequenceEqual(new[] { "AAA", "aaa", "aaaa", "abb" }));
+
+ items.Sort(OrderedComparer<string>.OrderByDescending(x => x.Length).ThenBy(x => x, StringComparer.Ordinal));
+ Assert.True(items.SequenceEqual(new[] { "aaaa", "AAA", "aaa", "abb" }));
+
+ items.Sort(OrderedComparer<string>.OrderBy(x => x.Length).ThenBy(x => x, StringComparer.Ordinal));
+ Assert.True(items.SequenceEqual(new[] { "AAA", "aaa", "abb", "aaaa" }));
+
+ items.Sort(OrderedComparer<string>.OrderBy(x => x.Length).ThenBy(x => x, StringComparer.OrdinalIgnoreCase));
+ Assert.True(items.SequenceEqual(new[] { "AAA", "AAA", "abb", "aaaa" }, StringComparer.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public void ChainOntoRegularIComparables()
+ {
+ var items = new List<string> { "aaa", "AAA", "abb", "aaaa" };
+ var comparer = StringComparer.OrdinalIgnoreCase;
+
+ items.Sort(comparer);
+ Assert.True(items.SequenceEqual(new[] { "AAA", "aaa", "aaaa", "abb" }, StringComparer.OrdinalIgnoreCase));
+
+ items.Sort(comparer.ThenByDescending(x => x, StringComparer.Ordinal));
+ Assert.True(items.SequenceEqual(new[] { "aaa", "AAA", "aaaa", "abb" }, StringComparer.Ordinal));
+ }
+
+ [Fact]
+ public void WorksWithAnonymousTypes()
+ {
+ var source = new List<string> { "abc", "bcd", "cde" };
+ var items = source.Select(x => new { FirstLetter = x[0], AllOfIt = x }).ToList();
+
+ items.Sort(OrderedComparer.For(items).OrderBy(x => x.FirstLetter));
+ Assert.True(items.Select(x => x.FirstLetter).SequenceEqual("abc"));
+
+ }
+ }
+}
View
1  ReactiveUI.Tests/ReactiveUI.Tests_Mono.csproj
@@ -67,6 +67,7 @@
<Compile Include="ObservableAsPropertyHelperTest.cs" />
<Compile Include="ObservableAsyncMRUCacheTest.cs" />
<Compile Include="ObservedChangedMixinTest.cs" />
+ <Compile Include="OrderedComparerTests.cs" />
<Compile Include="ReactiveCollectionTest.cs" />
<Compile Include="ReactiveCommandTest.cs" />
<Compile Include="ReactiveNotifyPropertyChangedMixinTest.cs" />
View
1  ReactiveUI.Tests/ReactiveUI.Tests_Net45.csproj
@@ -119,6 +119,7 @@
<Compile Include="MessageBusTest.cs" />
<Compile Include="ObservableAsPropertyHelperTest.cs" />
<Compile Include="ObservedChangedMixinTest.cs" />
+ <Compile Include="OrderedComparerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBindingTest.cs" />
<Compile Include="ReactiveCollectionTest.cs" />
View
1  ReactiveUI.Tests/ReactiveUI.Tests_SL5.csproj
@@ -149,6 +149,7 @@
<Compile Include="MessageBusTest.cs" />
<Compile Include="ObservableAsPropertyHelperTest.cs" />
<Compile Include="ObservableAsyncMRUCacheTest.cs" />
+ <Compile Include="OrderedComparerTests.cs" />
<Compile Include="ObservedChangedMixinTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBindingTest.cs" />
View
237 ReactiveUI/OrderedComparer.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Collections.Generic;
+
+namespace ReactiveUI
+{
+ /// <summary>
+ /// Convienience interface for providing a starting point for chaining comparers.
+ /// </summary>
+ public interface IComparerBuilder<T>
+ {
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in ascending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the default comparer for the return type of the selector.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ IComparer<T> OrderBy<TValue>(Func<T, TValue> selector);
+
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in ascending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the provided comparer or the default comparer for the return type of the selector if no
+ /// comparer is specified.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ IComparer<T> OrderBy<TValue>(Func<T, TValue> selector, IComparer<TValue> comparer);
+
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in descending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the default comparer for the return type of the selector.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ IComparer<T> OrderByDescending<TValue>(Func<T, TValue> selector);
+
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in descending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the provided comparer or the default comparer for the return type of the selector if no
+ /// comparer is specified.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ IComparer<T> OrderByDescending<TValue>(Func<T, TValue> selector, IComparer<TValue> comparer);
+ }
+
+ /// <summary>
+ /// Convienience class providing a starting point for chaining comparers for anonymous types.
+ /// </summary>
+ /// <remarks>
+ /// If the type you're creating a comparer for is known this class is nothing more than an alias for the generic
+ /// OrderedComparer. This class can be used to create comparers for anonymous types
+ /// </remarks>
+ public static class OrderedComparer
+ {
+ private sealed class OrderedComparerTypeWrapper<T> : IComparerBuilder<T>
+ {
+ public static readonly OrderedComparerTypeWrapper<T> Instance = new OrderedComparerTypeWrapper<T>();
+
+ public IComparer<T> OrderBy<TValue>(Func<T, TValue> selector)
+ {
+ return OrderedComparer<T>.OrderBy(selector);
+ }
+
+ public IComparer<T> OrderBy<TValue>(Func<T, TValue> selector, IComparer<TValue> comparer)
+ {
+ return OrderedComparer<T>.OrderBy(selector, comparer);
+ }
+
+ public IComparer<T> OrderByDescending<TValue>(Func<T, TValue> selector)
+ {
+ return OrderedComparer<T>.OrderByDescending(selector);
+ }
+
+ public IComparer<T> OrderByDescending<TValue>(Func<T, TValue> selector, IComparer<TValue> comparer)
+ {
+ return OrderedComparer<T>.OrderByDescending(selector, comparer);
+ }
+ }
+
+ /// <summary>
+ /// Creates a type inferred comparer builder for the element type of the enumerable. Useful for creating
+ /// comparers for anonymous types. Note that the builder is not a comparer in itself, you need to use the
+ /// OrderBy or OrderByDescending methods on the builder to get an actual comparer.
+ /// </summary>
+ public static IComparerBuilder<T> For<T>(IEnumerable<T> enumerable)
+ {
+ return For<T>();
+ }
+
+ /// <summary>
+ /// Creates a comparer builder for the specified type. Note that the builder is not a comparer in itself,
+ /// you need to use the OrderBy or OrderByDescending methods on the builder to get an actual comparer.
+ /// If the type is known at compile time this method is nothing more than an alias for the generic
+ /// OrdedComparer class.
+ /// </summary>
+ public static IComparerBuilder<T> For<T>()
+ {
+ return OrderedComparerTypeWrapper<T>.Instance;
+ }
+ }
+
+ /// <summary>
+ /// Convienience class providing a starting point for chaining comparers.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public static class OrderedComparer<T>
+ {
+ /// <summary>
+ /// Creates a comparer that will sort elements in ascending order based on the values returned by the provided
+ /// selector. The values will be compared using the default comparer for the return type of the selector.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ public static IComparer<T> OrderBy<TValue>(Func<T,TValue> selector)
+ {
+ return ComparerChainingExtensions.ThenBy<T, TValue>(null, selector);
+ }
+
+ /// <summary>
+ /// Creates a comparer that will sort elements in ascending order based on the values returned by the provided
+ /// selector. The selector values will be compared using the provided comparer or the default comparer for the
+ /// return type of the selector if no comparer is specified.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ /// <param name="comparer">
+ /// The comparer to use when comparing the values returned by the selector.
+ /// The default comparer for that type will be used if this parameter is null.
+ /// </param>
+ public static IComparer<T> OrderBy<TValue>(Func<T, TValue> selector, IComparer<TValue> comparer)
+ {
+ return ComparerChainingExtensions.ThenBy<T, TValue>(null, selector, comparer);
+ }
+
+ /// <summary>
+ /// Creates a comparer that will sort elements in descending order based on the values returned by the provided
+ /// selector. The values will be compared using the default comparer for the return type of the selector.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ public static IComparer<T> OrderByDescending<TValue>(Func<T, TValue> selector)
+ {
+ return ComparerChainingExtensions.ThenByDescending<T, TValue>(null, selector);
+ }
+
+ /// <summary>
+ /// Creates a comparer that will sort elements in descending order based on the values returned by the provided
+ /// selector. The selector values will be compared using the provided comparer or the default comparer for the
+ /// return type of the selector if no comparer is specified.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ /// <param name="comparer">
+ /// The comparer to use when comparing the values returned by the selector.
+ /// The default comparer for that type will be used if this parameter is null.
+ /// </param>
+ public static IComparer<T> OrderByDescending<TValue>(Func<T, TValue> selector, IComparer<TValue> comparer)
+ {
+ return ComparerChainingExtensions.ThenByDescending<T, TValue>(null, selector, comparer);
+ }
+ }
+
+ public static class ComparerChainingExtensions
+ {
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in ascending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the default comparer for the return type of the selector.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ public static IComparer<T> ThenBy<T, TValue>(this IComparer<T> parent, Func<T, TValue> selector)
+ {
+ return ThenBy(parent, selector, Comparer<TValue>.Default);
+ }
+
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in ascending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the provided comparer or the default comparer for the return type of the selector if no
+ /// comparer is specified.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ public static IComparer<T> ThenBy<T, TValue>(this IComparer<T> parent, Func<T, TValue> selector, IComparer<TValue> comparer)
+ {
+ return new ChainedComparer<T>(parent, (x, y) => comparer.Compare(selector(x), selector(y)));
+ }
+
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in descending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the default comparer for the return type of the selector.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ public static IComparer<T> ThenByDescending<T, TValue>(this IComparer<T> parent, Func<T, TValue> selector)
+ {
+ return ThenByDescending(parent, selector, Comparer<TValue>.Default);
+ }
+
+ /// <summary>
+ /// Creates a derived comparer based on the given parent comparer. The returned comparer will sort elements
+ /// using the parent comparer first. If the parent considers the values equal elements will be sorted
+ /// in descending order based on the values returned by the provided selector. The selector values will be
+ /// compared using the provided comparer or the default comparer for the return type of the selector if no
+ /// comparer is specified.
+ /// </summary>
+ /// <param name="selector">A function supplying the values for the comparator.</param>
+ public static IComparer<T> ThenByDescending<T, TValue>(this IComparer<T> parent, Func<T, TValue> selector, IComparer<TValue> comparer)
+ {
+ return new ChainedComparer<T>(parent, (x, y) => -comparer.Compare(selector(x), selector(y)));
+ }
+ }
+
+ internal sealed class ChainedComparer<T> : IComparer<T>
+ {
+ private IComparer<T> parent;
+ private Comparison<T> inner;
+
+ public ChainedComparer(IComparer<T> parent, Comparison<T> comparison)
+ {
+ if (comparison == null)
+ throw new ArgumentNullException("comparison");
+
+ this.parent = parent;
+ this.inner = comparison;
+ }
+
+ public int Compare(T x, T y)
+ {
+ int parentResult = parent == null ? 0 : parent.Compare(x, y);
+
+ return parentResult != 0 ? parentResult : inner(x, y);
+ }
+ }
+}
View
1  ReactiveUI/ReactiveUI.csproj
@@ -59,6 +59,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="POCOObservableForProperty.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBinding.cs" />
View
1  ReactiveUI/ReactiveUI_Mono.csproj
@@ -121,6 +121,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReactiveCollection.cs" />
<Compile Include="ReactiveNotifyPropertyChangedMixin.cs" />
View
1  ReactiveUI/ReactiveUI_Monodroid.csproj
@@ -127,6 +127,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReactiveCollection.cs" />
<Compile Include="ReactiveNotifyPropertyChangedMixin.cs" />
View
1  ReactiveUI/ReactiveUI_Monotouch.csproj
@@ -68,6 +68,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="POCOObservableForProperty.cs" />
<Compile Include="ReactiveCollection.cs" />
<Compile Include="ReactiveNotifyPropertyChangedMixin.cs" />
View
1  ReactiveUI/ReactiveUI_Net45.csproj
@@ -136,6 +136,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="POCOObservableForProperty.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBinding.cs" />
View
1  ReactiveUI/ReactiveUI_SL5.csproj
@@ -118,6 +118,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="POCOObservableForProperty.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBinding.cs" />
View
1  ReactiveUI/ReactiveUI_WP7.csproj
@@ -129,6 +129,7 @@
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservableToTaskShim.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="POCOObservableForProperty.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBinding.cs" />
View
1  ReactiveUI/ReactiveUI_WP8.csproj
@@ -119,6 +119,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="POCOObservableForProperty.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBinding.cs" />
View
1  ReactiveUI/ReactiveUI_WinRT.csproj
@@ -51,6 +51,7 @@
<Compile Include="ObservableAsPropertyHelper.cs" />
<Compile Include="ObservableAsyncMRUCache.cs" />
<Compile Include="ObservedChangedMixin.cs" />
+ <Compile Include="OrderedComparer.cs" />
<Compile Include="POCOObservableForProperty.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyBinding.cs" />
View
3  ReactiveUI/RxApp.cs
@@ -480,7 +480,7 @@ public static bool InUnitTestRunner(string[] testAssemblies, string[] designEnvi
// without access to any WPF references :-/
var entry = Assembly.GetEntryAssembly();
if (entry != null) {
- var exeName = entry.Location.ToUpperInvariant();
+ var exeName = (new FileInfo(entry.Location)).Name.ToUpperInvariant();
if (designEnvironments.Any(x => x.Contains(exeName))) {
return true;
@@ -514,6 +514,7 @@ public static bool InUnitTestRunner()
"BLEND.EXE",
"MONODEVELOP",
"SHARPDEVELOP.EXE",
+ "XDESPROC.EXE",
};
return InUnitTestRunner(testAssemblies, designEnvironments);
Please sign in to comment.
Something went wrong with that request. Please try again.