Skip to content

Commit daeb0d7

Browse files
committed
Fix Wrong UWP Scheduler
Fix for #2993
1 parent b32de3e commit daeb0d7

11 files changed

+133
-193
lines changed

src/Directory.build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
<PackageReference Include="Microsoft.Reactive.Testing" Version="5.0.0" />
5151
<PackageReference Include="PublicApiGenerator" Version="10.2.0" />
5252
<PackageReference Include="coverlet.msbuild" Version="3.1.0" PrivateAssets="All" />
53-
<PackageReference Include="Verify.Xunit" Version="14.0.1" />
53+
<PackageReference Include="Verify.Xunit" Version="14.1.1" />
5454
</ItemGroup>
5555

5656
<ItemGroup Condition="'$(IsTestProject)' != 'true'">

src/ReactiveUI.Tests/Platforms/windows-xaml/Api/XamlApiApprovalTests.Blend.Net4_8.received.txt

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/ReactiveUI.Tests/Platforms/winforms/API/WinformsApiApprovalTests.Winforms.DotNet5_0.received.txt

Lines changed: 0 additions & 119 deletions
This file was deleted.

src/ReactiveUI.Uwp/ActivationForViewFetcher.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class ActivationForViewFetcher : IActivationForViewFetcher
2525
/// <inheritdoc/>
2626
public IObservable<bool> GetActivationForView(IActivatableView view)
2727
{
28-
if (!(view is FrameworkElement fe))
28+
if (view is not FrameworkElement fe)
2929
{
3030
return Observable<bool>.Empty;
3131
}
@@ -54,4 +54,4 @@ public IObservable<bool> GetActivationForView(IActivatableView view)
5454
.Switch()
5555
.DistinctUntilChanged();
5656
}
57-
}
57+
}

src/ReactiveUI.Uwp/Common/AutoDataTemplateBindingHook.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public bool ExecuteHook(object? source, object target, Func<IObservedChange<obje
7474
var viewProperties = getCurrentViewProperties();
7575
var lastViewProperty = viewProperties.LastOrDefault();
7676

77-
if (!(lastViewProperty?.Sender is ItemsControl itemsControl))
77+
if (lastViewProperty?.Sender is not ItemsControl itemsControl)
7878
{
7979
return true;
8080
}

src/ReactiveUI.Uwp/PlatformRegistrations.cs

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/ReactiveUI.Uwp/Registrations.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,11 @@ public void Register(Action<Func<object>, Type> registerFunction)
3131
registerFunction(() => new AutoDataTemplateBindingHook(), typeof(IPropertyBindingHook));
3232

3333
registerFunction(() => new WinRTAppDataDriver(), typeof(ISuspensionDriver));
34+
35+
if (!ModeDetector.InUnitTestRunner())
36+
{
37+
RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
38+
RxApp.MainThreadScheduler = new SingleWindowDispatcherScheduler();
39+
}
3440
}
35-
}
41+
}

src/ReactiveUI.WinUI/DispatcherQueueScheduler.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ namespace System.Reactive.Concurrency
1313
/// <summary>
1414
/// Represents an object that schedules units of work on a <see cref="Microsoft.UI.Dispatching.DispatcherQueue"/>.
1515
/// </summary>
16-
/// <remarks>
17-
/// This scheduler type is typically used indirectly through the <see cref="Linq.DispatcherObservable.ObserveOnDispatcher{TSource}(IObservable{TSource})"/> and <see cref="Linq.DispatcherObservable.SubscribeOnDispatcher{TSource}(IObservable{TSource})"/> methods that use the Dispatcher on the calling thread.
18-
/// </remarks>
1916
public class DispatcherQueueScheduler : LocalScheduler, ISchedulerPeriodic
2017
{
2118
/// <summary>
@@ -47,7 +44,7 @@ public DispatcherQueueScheduler(DispatcherQueue dispatcherQueue)
4744
}
4845

4946
/// <summary>
50-
/// Constructs a <see cref="DispatcherScheduler"/> that schedules units of work on the given <see cref="Microsoft.UI.Dispatching.DispatcherQueue"/> at the given priority.
47+
/// Constructs a DispatcherScheduler that schedules units of work on the given <see cref="Microsoft.UI.Dispatching.DispatcherQueue"/> at the given priority.
5148
/// </summary>
5249
/// <param name="dispatcherQueue"><see cref="Microsoft.UI.Dispatching.DispatcherQueue"/> to schedule work on.</param>
5350
/// <param name="priority">Priority at which units of work are scheduled.</param>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved.
2+
// Licensed to the .NET Foundation under one or more agreements.
3+
// The .NET Foundation licenses this file to you under the MIT license.
4+
// See the LICENSE file in the project root for full license information.
5+
// <auto-generated />
6+
7+
using System;
8+
using System.ComponentModel;
9+
using Splat;
10+
11+
#nullable enable
12+
namespace ReactiveUI;
13+
14+
/// <summary>
15+
/// Binding Type Converter for component model.
16+
/// </summary>
17+
public class ComponentModelTypeConverter : IBindingTypeConverter
18+
{
19+
private readonly MemoizingMRUCache<(Type fromType, Type toType), TypeConverter?> _typeConverterCache = new (
20+
(types, _) =>
21+
{
22+
// NB: String is a Magical Type(tm) to TypeConverters. If we are
23+
// converting from string => int, we need the Int converter, not
24+
// the string converter :-/
25+
if (types.fromType == typeof(string))
26+
{
27+
types = (types.toType, types.fromType);
28+
}
29+
30+
var converter = TypeDescriptor.GetConverter(types.fromType);
31+
return converter.CanConvertTo(types.toType) ? converter : null;
32+
}, RxApp.SmallCacheLimit);
33+
34+
/// <inheritdoc/>
35+
public int GetAffinityForObjects(Type fromType, Type toType)
36+
{
37+
var converter = _typeConverterCache.Get((fromType, toType));
38+
return converter is not null ? 10 : 0;
39+
}
40+
41+
/// <inheritdoc/>
42+
public bool TryConvert(object? from, Type toType, object? conversionHint, out object? result)
43+
{
44+
if (from is null)
45+
{
46+
result = null;
47+
return true;
48+
}
49+
50+
var fromType = from.GetType();
51+
var converter = _typeConverterCache.Get((fromType, toType));
52+
53+
if (converter is null)
54+
{
55+
throw new ArgumentException($"Can't convert {fromType} to {toType}. To fix this, register a IBindingTypeConverter");
56+
}
57+
58+
try
59+
{
60+
// TODO: This should use conversionHint to determine whether this is locale-aware or not
61+
result = (fromType == typeof(string)) ?
62+
converter.ConvertFrom(from) : converter.ConvertTo(from, toType);
63+
64+
return true;
65+
}
66+
catch (FormatException)
67+
{
68+
result = null;
69+
return false;
70+
}
71+
catch (Exception e)
72+
{
73+
// Errors from ConvertFrom end up here but wrapped in
74+
// outer exception. Add more types here as required.
75+
// IndexOutOfRangeException is given when trying to
76+
// convert empty strings with some/all? converters
77+
if (e.InnerException is IndexOutOfRangeException ||
78+
e.InnerException is FormatException)
79+
{
80+
result = null;
81+
return false;
82+
}
83+
84+
throw new Exception($"Can't convert from {@from.GetType()} to {toType}.", e);
85+
}
86+
}
87+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved.
2+
// Licensed to the .NET Foundation under one or more agreements.
3+
// The .NET Foundation licenses this file to you under the MIT license.
4+
// See the LICENSE file in the project root for full license information.
5+
// <auto-generated />
6+
7+
using System;
8+
using System.Reactive.Concurrency;
9+
using Splat;
10+
11+
namespace ReactiveUI;
12+
13+
/// <summary>
14+
/// .NET Framework platform registrations.
15+
/// </summary>
16+
/// <seealso cref="ReactiveUI.IWantsToRegisterStuff" />
17+
public class PlatformRegistrations : IWantsToRegisterStuff
18+
{
19+
/// <inheritdoc/>
20+
public void Register(Action<Func<object>, Type> registerFunction)
21+
{
22+
if (registerFunction is null)
23+
{
24+
throw new ArgumentNullException(nameof(registerFunction));
25+
}
26+
// Registration is done in Registrations of ReactiveUI.Uap
27+
}
28+
}

0 commit comments

Comments
 (0)