From 022d778a0f6c299277966d9665fb86c0459c0291 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Mon, 10 Jul 2023 08:03:59 +0100 Subject: [PATCH] Housekeeping : Migrate Uwp files to Wpf, update WinForms (#3578) --- .../ActivationForViewFetcher.cs | 57 ----- src/ReactiveUI.Uwp/AutoSuspendHelper.cs | 105 -------- .../DependencyObjectObservableForProperty.cs | 165 ------------ src/ReactiveUI.Uwp/ReactiveUI.Uwp.csproj | 21 -- src/ReactiveUI.Uwp/ReactiveUI.rd.xml | 8 - src/ReactiveUI.Uwp/Registrations.cs | 41 --- .../SingleWindowDispatcherScheduler.cs | 238 ------------------ .../TransitioningContentControl.Empty.cs | 30 --- src/ReactiveUI.Uwp/WinRTAppDataDriver.cs | 70 ------ .../ReactiveUI.Winforms.csproj | 15 +- .../Common/AutoDataTemplateBindingHook.cs | 30 --- .../Common/BooleanToVisibilityHint.cs | 0 .../BooleanToVisibilityTypeConverter.cs | 0 .../Common/PlatformOperations.cs | 0 .../Common/ReactivePage.cs | 0 .../Common/ReactiveUserControl.cs | 0 .../Common/RoutedViewHost.cs | 0 .../Common/ViewModelViewHost.cs | 0 src/ReactiveUI.Wpf/ReactiveUI.Wpf.csproj | 11 +- .../Rx/Concurrency/ControlScheduler.cs | 0 .../Rx/Concurrency/DispatcherScheduler.cs | 0 .../Rx/Internal/Constants.cs | 0 .../Rx/Linq/ControlObservable.cs | 0 .../Rx/Linq/DispatcherObservable.cs | 0 .../Rx/Linq/Observable.Remoting.cs | 0 .../Rx/Linq/QueryLanguage.Remoting.cs | 0 26 files changed, 10 insertions(+), 781 deletions(-) delete mode 100644 src/ReactiveUI.Uwp/ActivationForViewFetcher.cs delete mode 100644 src/ReactiveUI.Uwp/AutoSuspendHelper.cs delete mode 100644 src/ReactiveUI.Uwp/DependencyObjectObservableForProperty.cs delete mode 100644 src/ReactiveUI.Uwp/ReactiveUI.Uwp.csproj delete mode 100644 src/ReactiveUI.Uwp/ReactiveUI.rd.xml delete mode 100644 src/ReactiveUI.Uwp/Registrations.cs delete mode 100644 src/ReactiveUI.Uwp/SingleWindowDispatcherScheduler.cs delete mode 100644 src/ReactiveUI.Uwp/TransitioningContentControl.Empty.cs delete mode 100644 src/ReactiveUI.Uwp/WinRTAppDataDriver.cs rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/AutoDataTemplateBindingHook.cs (76%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/BooleanToVisibilityHint.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/BooleanToVisibilityTypeConverter.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/PlatformOperations.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/ReactivePage.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/ReactiveUserControl.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/RoutedViewHost.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Common/ViewModelViewHost.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Rx/Concurrency/ControlScheduler.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Rx/Concurrency/DispatcherScheduler.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Rx/Internal/Constants.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Rx/Linq/ControlObservable.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Rx/Linq/DispatcherObservable.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Rx/Linq/Observable.Remoting.cs (100%) rename src/{ReactiveUI.Uwp => ReactiveUI.Wpf}/Rx/Linq/QueryLanguage.Remoting.cs (100%) diff --git a/src/ReactiveUI.Uwp/ActivationForViewFetcher.cs b/src/ReactiveUI.Uwp/ActivationForViewFetcher.cs deleted file mode 100644 index 6cd209f445..0000000000 --- a/src/ReactiveUI.Uwp/ActivationForViewFetcher.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using System.Reactive.Linq; -using System.Reflection; -using Windows.Foundation; -using Windows.UI.Xaml; - -namespace ReactiveUI; - -/// -/// ActiveationForViewFetcher is how ReactiveUI determine when a -/// View is activated or deactivated. This is usually only used when porting -/// ReactiveUI to a new UI framework. -/// -public class ActivationForViewFetcher : IActivationForViewFetcher -{ - /// - public int GetAffinityForView(Type view) => typeof(FrameworkElement).GetTypeInfo().IsAssignableFrom(view.GetTypeInfo()) ? 10 : 0; - - /// - public IObservable GetActivationForView(IActivatableView view) - { - if (view is not FrameworkElement fe) - { - return Observable.Empty; - } - - var viewLoaded = Observable.FromEvent, bool>( - eventHandler => - { - void Handler(FrameworkElement sender, object e) => eventHandler(true); - return Handler; - }, - x => fe.Loading += x, - x => fe.Loading -= x); - - var viewUnloaded = Observable.FromEvent( - eventHandler => - { - void Handler(object sender, RoutedEventArgs e) => eventHandler(false); - return Handler; - }, - x => fe.Unloaded += x, - x => fe.Unloaded -= x); - - return viewLoaded - .Merge(viewUnloaded) - .Select(b => b ? fe.WhenAnyValue(x => x.IsHitTestVisible).SkipWhile(x => !x) : Observables.False) - .Switch() - .DistinctUntilChanged(); - } -} diff --git a/src/ReactiveUI.Uwp/AutoSuspendHelper.cs b/src/ReactiveUI.Uwp/AutoSuspendHelper.cs deleted file mode 100644 index 776a7b0bbe..0000000000 --- a/src/ReactiveUI.Uwp/AutoSuspendHelper.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using System.Reactive; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Threading.Tasks; -using Splat; -using Windows.ApplicationModel; -using Windows.ApplicationModel.Activation; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; - -namespace ReactiveUI; - -/// -/// AutoSuspend-based Application. To use AutoSuspend with WinRT, change your -/// Application to inherit from this class, then call: -/// Locator.Current.GetService.<ISuspensionHost>().SetupDefaultSuspendResume(); -/// This will register your suspension host. -/// -public class AutoSuspendHelper : IEnableLogger, IDisposable -{ - private readonly ReplaySubject _activated = new(1); - - private bool _isDisposed; - - /// - /// Initializes a new instance of the class. - /// - /// The application. - public AutoSuspendHelper(Application app) - { - if (app is null) - { - throw new ArgumentNullException(nameof(app)); - } - - Reflection.ThrowIfMethodsNotOverloaded("AutoSuspendHelper", app, "OnLaunched"); - - var launchNew = new[] { ApplicationExecutionState.ClosedByUser, ApplicationExecutionState.NotRunning, }; - RxApp.SuspensionHost.IsLaunchingNew = _activated - .Where(x => launchNew.Contains(x.PreviousExecutionState)) - .Select(_ => Unit.Default); - - RxApp.SuspensionHost.IsResuming = _activated - .Where(x => x.PreviousExecutionState == ApplicationExecutionState.Terminated) - .Select(_ => Unit.Default); - - var unpausing = new[] { ApplicationExecutionState.Suspended, ApplicationExecutionState.Running, }; - RxApp.SuspensionHost.IsUnpausing = _activated - .Where(x => unpausing.Contains(x.PreviousExecutionState)) - .Select(_ => Unit.Default); - - var shouldPersistState = new Subject(); - app.Suspending += (_, e) => shouldPersistState.OnNext(e); - RxApp.SuspensionHost.ShouldPersistState = - shouldPersistState.Select(x => - { - var deferral = x.SuspendingOperation.GetDeferral(); - return Disposable.Create(deferral.Complete); - }); - - var shouldInvalidateState = new Subject(); - app.UnhandledException += (_, __) => shouldInvalidateState.OnNext(Unit.Default); - RxApp.SuspensionHost.ShouldInvalidateState = shouldInvalidateState; - } - - /// - /// Raises the applications Launch event. - /// - /// The instance containing the event data. - public void OnLaunched(IActivatedEventArgs args) => _activated.OnNext(args); - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Disposes of resources inside the class. - /// - /// If we are disposing managed resources. - protected virtual void Dispose(bool isDisposing) - { - if (_isDisposed) - { - return; - } - - if (isDisposing) - { - _activated?.Dispose(); - } - - _isDisposed = true; - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Uwp/DependencyObjectObservableForProperty.cs b/src/ReactiveUI.Uwp/DependencyObjectObservableForProperty.cs deleted file mode 100644 index d73037aaa2..0000000000 --- a/src/ReactiveUI.Uwp/DependencyObjectObservableForProperty.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Globalization; -using System.Linq.Expressions; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Reflection; -using Splat; -#if HAS_WINUI -using Microsoft.UI.Xaml; -#else -using Windows.UI.Xaml; -#endif - -#if HAS_UNO -namespace ReactiveUI.Uno -#else -namespace ReactiveUI -#endif -{ - /// - /// Creates a observable for a property if available that is based on a DependencyProperty. - /// - public class DependencyObjectObservableForProperty : ICreatesObservableForProperty - { - /// - public int GetAffinityForObject(Type type, string propertyName, bool beforeChanged = false) - { - if (!typeof(DependencyObject).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) - { - return 0; - } - - if (GetDependencyPropertyFetcher(type, propertyName) is null) - { - return 0; - } - - return 6; - } - - /// - public IObservable> GetNotificationForProperty(object sender, Expression expression, string propertyName, bool beforeChanged = false, bool suppressWarnings = false) - { - if (sender is null) - { - throw new ArgumentNullException(nameof(sender)); - } - - if (sender is not DependencyObject depSender) - { - throw new ArgumentException("The sender must be a DependencyObject", nameof(sender)); - } - - var type = sender.GetType(); - - if (beforeChanged) - { - this.Log().Warn( - CultureInfo.InvariantCulture, - "Tried to bind DO {0}.{1}, but DPs can't do beforeChanged. Binding as POCO object", - type.FullName, - propertyName); - - var ret = new POCOObservableForProperty(); - return ret.GetNotificationForProperty(sender, expression, propertyName, beforeChanged, suppressWarnings); - } - - var dpFetcher = GetDependencyPropertyFetcher(type, propertyName); - if (dpFetcher is null) - { - this.Log().Warn( - CultureInfo.InvariantCulture, - "Tried to bind DO {0}.{1}, but DP doesn't exist. Binding as POCO object", - type.FullName, - propertyName); - - var ret = new POCOObservableForProperty(); - return ret.GetNotificationForProperty(sender, expression, propertyName, beforeChanged, suppressWarnings); - } - - return Observable.Create>(subj => - { - var handler = new DependencyPropertyChangedCallback((_, _) => - subj.OnNext(new ObservedChange(sender, expression, default))); - - var dependencyProperty = dpFetcher(); - var token = depSender.RegisterPropertyChangedCallback(dependencyProperty, handler); - return Disposable.Create(() => depSender.UnregisterPropertyChangedCallback(dependencyProperty, token)); - }); - } - - private static PropertyInfo? ActuallyGetProperty(TypeInfo typeInfo, string propertyName) - { - var current = typeInfo; - while (current is not null) - { - var ret = current.GetDeclaredProperty(propertyName); - if (ret?.IsStatic() == true) - { - return ret; - } - - current = current.BaseType?.GetTypeInfo(); - } - - return null; - } - - private static FieldInfo? ActuallyGetField(TypeInfo typeInfo, string propertyName) - { - var current = typeInfo; - while (current is not null) - { - var ret = current.GetDeclaredField(propertyName); - if (ret?.IsStatic == true) - { - return ret; - } - - current = current.BaseType?.GetTypeInfo(); - } - - return null; - } - - private static Func? GetDependencyPropertyFetcher(Type type, string propertyName) - { - var typeInfo = type.GetTypeInfo(); - - // Look for the DependencyProperty attached to this property name - var pi = ActuallyGetProperty(typeInfo, propertyName + "Property"); - if (pi is not null) - { - var value = pi.GetValue(null); - - if (value is null) - { - return null; - } - - return () => (DependencyProperty)value; - } - - var fi = ActuallyGetField(typeInfo, propertyName + "Property"); - if (fi is not null) - { - var value = fi.GetValue(null); - - if (value is null) - { - return null; - } - - return () => (DependencyProperty)value; - } - - return null; - } - } -} diff --git a/src/ReactiveUI.Uwp/ReactiveUI.Uwp.csproj b/src/ReactiveUI.Uwp/ReactiveUI.Uwp.csproj deleted file mode 100644 index 5bf3f8e7b2..0000000000 --- a/src/ReactiveUI.Uwp/ReactiveUI.Uwp.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - uap10.0.17763 - Provides ReactiveUI extensions for the UWP Library - $(DefineConstants);NETFX_CORE - - - - - - - - - - - - - - - diff --git a/src/ReactiveUI.Uwp/ReactiveUI.rd.xml b/src/ReactiveUI.Uwp/ReactiveUI.rd.xml deleted file mode 100644 index 733ee7541c..0000000000 --- a/src/ReactiveUI.Uwp/ReactiveUI.rd.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/ReactiveUI.Uwp/Registrations.cs b/src/ReactiveUI.Uwp/Registrations.cs deleted file mode 100644 index accab90851..0000000000 --- a/src/ReactiveUI.Uwp/Registrations.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Reactive.Concurrency; - -using Splat; - -namespace ReactiveUI.Uwp; - -/// -/// .NET Framework platform registrations. -/// -/// -public class Registrations : IWantsToRegisterStuff -{ - /// - public void Register(Action, Type> registerFunction) - { - if (registerFunction is null) - { - throw new ArgumentNullException(nameof(registerFunction)); - } - - registerFunction(() => new PlatformOperations(), typeof(IPlatformOperations)); - registerFunction(() => new ActivationForViewFetcher(), typeof(IActivationForViewFetcher)); - registerFunction(() => new DependencyObjectObservableForProperty(), typeof(ICreatesObservableForProperty)); - registerFunction(() => new BooleanToVisibilityTypeConverter(), typeof(IBindingTypeConverter)); - registerFunction(() => new AutoDataTemplateBindingHook(), typeof(IPropertyBindingHook)); - - registerFunction(() => new WinRTAppDataDriver(), typeof(ISuspensionDriver)); - - if (!ModeDetector.InUnitTestRunner()) - { - RxApp.TaskpoolScheduler = TaskPoolScheduler.Default; - RxApp.MainThreadScheduler = new SingleWindowDispatcherScheduler(); - } - } -} diff --git a/src/ReactiveUI.Uwp/SingleWindowDispatcherScheduler.cs b/src/ReactiveUI.Uwp/SingleWindowDispatcherScheduler.cs deleted file mode 100644 index 701be5552e..0000000000 --- a/src/ReactiveUI.Uwp/SingleWindowDispatcherScheduler.cs +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.Linq; -using System.Reactive.Concurrency; -using System.Reactive.Disposables; -using System.Reactive.PlatformServices; -using System.Runtime.ExceptionServices; -using System.Threading; -using Windows.ApplicationModel.Core; -using Windows.System.Threading; -using Windows.UI.Core; -using Windows.UI.Xaml; - -namespace ReactiveUI; - -/// -/// This scheduler forces all dispatching to go to the first window of the enumeration. -/// This makes the intended behavior of only supporting single window apps on UWP explicit. -/// If your app creates multiple windows, you should explicitly supply a scheduler which marshals -/// back to that window's . -/// -/// -/// This follows patterns set out in with some minor tweaks -/// for thread-safety and performance. -/// -/// -public class SingleWindowDispatcherScheduler : IScheduler -{ - private const CoreDispatcherPriority Priority = default; - private static CoreDispatcher? _dispatcher; - - /// - /// Initializes a new instance of the class. - /// - public SingleWindowDispatcherScheduler() - { - if (CoreApplication.Views.Count == 0) - { - return; - } - - var coreDispatcher = TryGetDispatcher(); - - Interlocked.CompareExchange(ref _dispatcher, coreDispatcher, null); - } - - /// - /// Initializes a new instance of the class with an explicit dispatcher. - /// - /// - /// The explicit to use. If you supply a dispatcher here then all instances of - /// will dispatch to that dispatcher from instantiation on. - /// - /// - /// dispatcher - To override the scheduler you must supply a non-null instance of CoreDispatcher. - /// - public SingleWindowDispatcherScheduler(CoreDispatcher dispatcher) => _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher), "To override the scheduler you must supply a non-null instance of CoreDispatcher."); - - /// - public DateTimeOffset Now => SystemClock.UtcNow; - - /// - public IDisposable Schedule(TState state, Func action) - { - if (action is null) - { - throw new ArgumentNullException(nameof(action)); - } - - if (CoreApplication.Views.Count == 0) - { - return CurrentThreadScheduler.Instance.Schedule(state, action); - } - - return ScheduleOnDispatcherNow(state, action); - } - - /// - public IDisposable Schedule(TState state, TimeSpan dueTime, Func action) - { - if (action is null) - { - throw new ArgumentNullException(nameof(action)); - } - - if (CoreApplication.Views.Count == 0) - { - return CurrentThreadScheduler.Instance.Schedule(state, dueTime, action); - } - - var dt = Scheduler.Normalize(dueTime); - if (dt.Ticks == 0) - { - return ScheduleOnDispatcherNow(state, action); - } - - return ScheduleSlow(state, dt, action); - } - - /// - public IDisposable Schedule(TState state, DateTimeOffset dueTime, Func action) - { - if (action is null) - { - throw new ArgumentNullException(nameof(action)); - } - - if (CoreApplication.Views.Count == 0) - { - return CurrentThreadScheduler.Instance.Schedule(state, dueTime, action); - } - - var dt = Scheduler.Normalize(dueTime - DateTimeOffset.Now); - if (dt.Ticks == 0) - { - return ScheduleOnDispatcherNow(state, action); - } - - return ScheduleSlow(state, dt, action); - } - - /// - /// Work-around for the behavior of throwing from "async void" or an not propagating - /// the exception to the event as users have come to expect from - /// previous XAML stacks using Rx. - /// - /// The exception. - private static void RaiseUnhandledException(Exception ex) - { - var timer = new DispatcherTimer - { - Interval = TimeSpan.Zero - }; - - timer.Tick += RaiseToDispatcher; - - timer.Start(); -#pragma warning disable RCS1163 // Unused parameter. - void RaiseToDispatcher(object sender, object e) -#pragma warning restore RCS1163 // Unused parameter. - { - timer.Stop(); - timer.Tick -= RaiseToDispatcher; - timer = null; - - ExceptionDispatchInfo.Capture(ex).Throw(); - } - } - - private static CoreDispatcher? TryGetDispatcher() - { - CoreDispatcher? coreDispatcher; - - try - { - coreDispatcher = CoreApplication.Views.Count > 0 ? CoreApplication.Views[0].Dispatcher : null; - } - catch - { - // in the XamlIsland case, accessing Views throws. Thus, falling back to the old way. This HAS to be initialized on the MainThread. - coreDispatcher = Window.Current?.Dispatcher; - } - - return coreDispatcher; - } - - private IDisposable ScheduleOnDispatcherNow(TState state, Func action) - { - try - { - // if _dispatcher is still null (and only then) CompareExchange it with the dispatcher from the first view found - if (_dispatcher is null) - { - var dispatcher = TryGetDispatcher(); - Interlocked.CompareExchange(ref _dispatcher, dispatcher, null); - } - } - catch - { - // Ignore - } - - if (_dispatcher is null || _dispatcher.HasThreadAccess) - { - return action(this, state); - } - - var d = new SingleAssignmentDisposable(); - - var dispatchResult = _dispatcher.RunAsync( - Priority, - () => - { - if (!d.IsDisposed) - { - try - { - d.Disposable = action(this, state); - } - catch (Exception ex) - { - RaiseUnhandledException(ex); - } - } - }); - - return StableCompositeDisposable.Create( - d, - Disposable.Create(() => dispatchResult.Cancel())); - } - - private IDisposable ScheduleSlow(TState state, TimeSpan dueTime, Func action) - { - var d = new MultipleAssignmentDisposable(); - - // Why ThreadPoolTimer? - // -- - // Because, we can't guarantee that DispatcherTimer will dispatch to the correct CoreDispatcher if there are multiple - // so we dispatch explicitly from our own method. - var timer = ThreadPoolTimer.CreateTimer(_ => d.Disposable = ScheduleOnDispatcherNow(state, action), dueTime); - - d.Disposable = Disposable.Create(() => - { - var t = Interlocked.Exchange(ref timer, null!); - if (t is not null) - { - t.Cancel(); - action = (_, __) => Disposable.Empty; - } - }); - - return d; - } -} \ No newline at end of file diff --git a/src/ReactiveUI.Uwp/TransitioningContentControl.Empty.cs b/src/ReactiveUI.Uwp/TransitioningContentControl.Empty.cs deleted file mode 100644 index ef279c19d9..0000000000 --- a/src/ReactiveUI.Uwp/TransitioningContentControl.Empty.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Diagnostics.CodeAnalysis; -#if HAS_WINUI -using Microsoft.UI.Xaml.Controls; -#else -using Windows.UI.Xaml.Controls; -#endif - -#if HAS_UNO -namespace ReactiveUI.Uno -#else -namespace ReactiveUI -#endif -{ - /// - /// A control with a single transition. - /// - [SuppressMessage("Design", "CA1010:Collections should implement generic interface", Justification = "Deliberate usage")] - public -#if HAS_UNO - partial -#endif - class TransitioningContentControl : ContentControl - { - } -} diff --git a/src/ReactiveUI.Uwp/WinRTAppDataDriver.cs b/src/ReactiveUI.Uwp/WinRTAppDataDriver.cs deleted file mode 100644 index 07b3a99de2..0000000000 --- a/src/ReactiveUI.Uwp/WinRTAppDataDriver.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved. -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; -using System.IO; -using System.Linq; -using System.Reactive; -using System.Reactive.Linq; -using System.Reactive.Windows.Foundation; -using System.Runtime.Serialization; -using System.Text; -using Windows.Storage; -using UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding; - -namespace ReactiveUI; - -/// -/// Loads and saves state to persistent storage. -/// -public class WinRTAppDataDriver : ISuspensionDriver -{ - /// - public IObservable LoadState() => - ApplicationData.Current.RoamingFolder.GetFileAsync("appData.xmlish").ToObservable() - .SelectMany(x => FileIO.ReadTextAsync(x, UnicodeEncoding.Utf8)) - .SelectMany(x => - { - var line = x.IndexOf('\n'); - var typeName = x.Substring(0, line - 1); // -1 for CR - var serializer = new DataContractSerializer(Type.GetType(typeName)); - - // NB: WinRT is terrible - var obj = serializer.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(x.Substring(line + 1)))); - return Observable.Return(obj); - }); - - /// - public IObservable SaveState(object state) - { - if (state is null) - { - throw new ArgumentNullException(nameof(state)); - } - - try - { - var ms = new MemoryStream(); - var writer = new StreamWriter(ms, Encoding.UTF8); - var serializer = new DataContractSerializer(state.GetType()); - writer.WriteLine(state.GetType().AssemblyQualifiedName); - writer.Flush(); - - serializer.WriteObject(ms, state); - - return ApplicationData.Current.RoamingFolder.CreateFileAsync("appData.xmlish", CreationCollisionOption.ReplaceExisting).ToObservable() - .SelectMany(x => FileIO.WriteBytesAsync(x, ms.ToArray()).ToObservable()); - } - catch (Exception ex) - { - return Observable.Throw(ex); - } - } - - /// - public IObservable InvalidateState() => - ApplicationData.Current.RoamingFolder.GetFileAsync("appData.xmlish").ToObservable() - .SelectMany(x => x.DeleteAsync().ToObservable()); -} \ No newline at end of file diff --git a/src/ReactiveUI.Winforms/ReactiveUI.Winforms.csproj b/src/ReactiveUI.Winforms/ReactiveUI.Winforms.csproj index 06ef08186f..ab1dca659b 100644 --- a/src/ReactiveUI.Winforms/ReactiveUI.Winforms.csproj +++ b/src/ReactiveUI.Winforms/ReactiveUI.Winforms.csproj @@ -1,7 +1,10 @@  - + - net462;net472;net48;net6.0-windows10.0.17763.0;net7.0-windows10.0.17763.0 + net462;net472;net48;net6.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net6.0-windows10.0.19041.0;net7.0-windows10.0.19041.0 ReactiveUI.Winforms ReactiveUI.Winforms Contains the ReactiveUI platform specific extensions for Windows Forms @@ -16,12 +19,10 @@ - + - - - - + + diff --git a/src/ReactiveUI.Uwp/Common/AutoDataTemplateBindingHook.cs b/src/ReactiveUI.Wpf/Common/AutoDataTemplateBindingHook.cs similarity index 76% rename from src/ReactiveUI.Uwp/Common/AutoDataTemplateBindingHook.cs rename to src/ReactiveUI.Wpf/Common/AutoDataTemplateBindingHook.cs index 46b07ed0d9..062c5172e4 100644 --- a/src/ReactiveUI.Uwp/Common/AutoDataTemplateBindingHook.cs +++ b/src/ReactiveUI.Wpf/Common/AutoDataTemplateBindingHook.cs @@ -3,30 +3,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -#if !HAS_MAUI using System; -using System.Diagnostics.CodeAnalysis; using System.Linq; - -#if HAS_WINUI -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Markup; -#elif NETFX_CORE || HAS_UNO -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Markup; -#else using System.Windows; using System.Windows.Controls; using System.Windows.Markup; -#endif -#if HAS_UNO -namespace ReactiveUI.Uno -#else namespace ReactiveUI -#endif { /// /// AutoDataTemplateBindingHook is a binding hook that checks ItemsControls @@ -40,13 +23,6 @@ public class AutoDataTemplateBindingHook : IPropertyBindingHook /// public static Lazy DefaultItemTemplate { get; } = new(() => { -#if NETFX_CORE || HAS_UNO - const string template = -@" - -"; - return (DataTemplate)XamlReader.Load(template); -#else const string template = " " + "" + @@ -55,12 +31,7 @@ public class AutoDataTemplateBindingHook : IPropertyBindingHook var assemblyName = typeof(AutoDataTemplateBindingHook).Assembly.FullName; assemblyName = assemblyName?.Substring(0, assemblyName.IndexOf(',')); -#if HAS_WINUI - return (DataTemplate)XamlReader.Load(template.Replace("__ASSEMBLYNAME__", assemblyName)); -#else return (DataTemplate)XamlReader.Parse(template.Replace("__ASSEMBLYNAME__", assemblyName)); -#endif -#endif }); /// @@ -104,4 +75,3 @@ public bool ExecuteHook(object? source, object target, Func - - - - - - - + - - + diff --git a/src/ReactiveUI.Uwp/Rx/Concurrency/ControlScheduler.cs b/src/ReactiveUI.Wpf/Rx/Concurrency/ControlScheduler.cs similarity index 100% rename from src/ReactiveUI.Uwp/Rx/Concurrency/ControlScheduler.cs rename to src/ReactiveUI.Wpf/Rx/Concurrency/ControlScheduler.cs diff --git a/src/ReactiveUI.Uwp/Rx/Concurrency/DispatcherScheduler.cs b/src/ReactiveUI.Wpf/Rx/Concurrency/DispatcherScheduler.cs similarity index 100% rename from src/ReactiveUI.Uwp/Rx/Concurrency/DispatcherScheduler.cs rename to src/ReactiveUI.Wpf/Rx/Concurrency/DispatcherScheduler.cs diff --git a/src/ReactiveUI.Uwp/Rx/Internal/Constants.cs b/src/ReactiveUI.Wpf/Rx/Internal/Constants.cs similarity index 100% rename from src/ReactiveUI.Uwp/Rx/Internal/Constants.cs rename to src/ReactiveUI.Wpf/Rx/Internal/Constants.cs diff --git a/src/ReactiveUI.Uwp/Rx/Linq/ControlObservable.cs b/src/ReactiveUI.Wpf/Rx/Linq/ControlObservable.cs similarity index 100% rename from src/ReactiveUI.Uwp/Rx/Linq/ControlObservable.cs rename to src/ReactiveUI.Wpf/Rx/Linq/ControlObservable.cs diff --git a/src/ReactiveUI.Uwp/Rx/Linq/DispatcherObservable.cs b/src/ReactiveUI.Wpf/Rx/Linq/DispatcherObservable.cs similarity index 100% rename from src/ReactiveUI.Uwp/Rx/Linq/DispatcherObservable.cs rename to src/ReactiveUI.Wpf/Rx/Linq/DispatcherObservable.cs diff --git a/src/ReactiveUI.Uwp/Rx/Linq/Observable.Remoting.cs b/src/ReactiveUI.Wpf/Rx/Linq/Observable.Remoting.cs similarity index 100% rename from src/ReactiveUI.Uwp/Rx/Linq/Observable.Remoting.cs rename to src/ReactiveUI.Wpf/Rx/Linq/Observable.Remoting.cs diff --git a/src/ReactiveUI.Uwp/Rx/Linq/QueryLanguage.Remoting.cs b/src/ReactiveUI.Wpf/Rx/Linq/QueryLanguage.Remoting.cs similarity index 100% rename from src/ReactiveUI.Uwp/Rx/Linq/QueryLanguage.Remoting.cs rename to src/ReactiveUI.Wpf/Rx/Linq/QueryLanguage.Remoting.cs