浏览代码

Added Win32PlatformOptions.ShouldRenderOnUIThread

Fixes WPF interop
Julien Lebosquain 2 年之前
父节点
当前提交
7d879cf6fe

+ 9 - 2
samples/interop/WindowsInteropTest/Program.cs

@@ -1,5 +1,4 @@
 using System;
-using Avalonia.Controls;
 using ControlCatalog;
 using Avalonia;
 
@@ -15,7 +14,15 @@ namespace WindowsInteropTest
         {
             System.Windows.Forms.Application.EnableVisualStyles();
             System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
-            AppBuilder.Configure<App>().UseWin32().UseDirect2D1().SetupWithoutStarting();
+            AppBuilder.Configure<App>()
+                .UseWin32()
+                .UseDirect2D1()
+                .With(new Win32PlatformOptions
+                {
+                    UseWindowsUIComposition = false,
+                    ShouldRenderOnUIThread = true // necessary for WPF
+                })
+                .SetupWithoutStarting();
             System.Windows.Forms.Application.Run(new SelectorForm());
         }
     }

+ 2 - 3
src/Avalonia.Base/Rendering/DefaultRenderTimer.cs

@@ -1,6 +1,4 @@
 using System;
-using System.Diagnostics;
-using System.Threading.Tasks;
 using Avalonia.Platform;
 
 namespace Avalonia.Rendering
@@ -59,7 +57,8 @@ namespace Avalonia.Rendering
             }
         }
 
-        public bool RunsInBackground => true;
+        /// <inheritdoc />
+        public virtual bool RunsInBackground => true;
 
         /// <summary>
         /// Starts the timer.

+ 4 - 1
src/Avalonia.Base/Rendering/IRenderLoop.cs

@@ -27,7 +27,10 @@ namespace Avalonia.Rendering
         /// </summary>
         /// <param name="i">The update task.</param>
         void Remove(IRenderLoopTask i);
-        
+
+        /// <summary>
+        /// Indicates if the rendering is done on a non-UI thread.
+        /// </summary>
         bool RunsInBackground { get; }
     }
 }

+ 1 - 0
src/Avalonia.Base/Rendering/RenderLoop.cs

@@ -87,6 +87,7 @@ namespace Avalonia.Rendering
             }
         }
 
+        /// <inheritdoc />
         public bool RunsInBackground => Timer.RunsInBackground;
 
         private void TimerTick(TimeSpan time)

+ 8 - 1
src/Avalonia.Base/Rendering/UiThreadRenderTimer.cs

@@ -8,13 +8,20 @@ namespace Avalonia.Rendering
     /// <summary>
     /// Render timer that ticks on UI thread. Useful for debugging or bootstrapping on new platforms 
     /// </summary>
-    
     public class UiThreadRenderTimer : DefaultRenderTimer
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="UiThreadRenderTimer"/> class.
+        /// </summary>
+        /// <param name="framesPerSecond">The number of frames per second at which the loop should run.</param>
         public UiThreadRenderTimer(int framesPerSecond) : base(framesPerSecond)
         {
         }
 
+        /// <inheritdoc />
+        public override bool RunsInBackground => false;
+
+        /// <inheritdoc />
         protected override IDisposable StartCore(Action<TimeSpan> tick)
         {
             bool cancelled = false;

+ 1 - 8
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@@ -45,13 +45,6 @@ namespace Avalonia.Win32.Interop.Wpf
                 ((FrameworkElement)PlatformImpl)?.InvalidateMeasure();
             }
 
-            protected override void HandleResized(Size clientSize, PlatformResizeReason reason)
-            {
-                ClientSize = clientSize;
-                LayoutManager.ExecuteLayoutPass();
-                Renderer?.Resized(clientSize);
-            }
-
             public Size AllocatedSize => ClientSize;
         }
 
@@ -223,7 +216,7 @@ namespace Avalonia.Win32.Interop.Wpf
                 (Key)e.Key,
                 GetModifiers(null)));
 
-        protected override void OnTextInput(TextCompositionEventArgs e) 
+        protected override void OnTextInput(TextCompositionEventArgs e)
             => _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot, e.Text));
 
         void ITopLevelImpl.SetCursor(ICursorImpl cursor)

+ 17 - 7
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -6,12 +6,10 @@ using System.IO;
 using Avalonia.Reactive;
 using System.Runtime.InteropServices;
 using System.Threading;
-using Avalonia.Controls;
 using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Controls.Platform;
 using Avalonia.Input;
 using Avalonia.Input.Platform;
-using Avalonia.Media;
 using Avalonia.OpenGL;
 using Avalonia.Platform;
 using Avalonia.Rendering;
@@ -20,7 +18,6 @@ using Avalonia.Threading;
 using Avalonia.Utilities;
 using Avalonia.Win32.Input;
 using Avalonia.Win32.Interop;
-using Avalonia.Win32.WinRT;
 using static Avalonia.Win32.Interop.UnmanagedMethods;
 
 namespace Avalonia
@@ -68,6 +65,7 @@ namespace Avalonia
 
         /// <summary>
         /// Render Avalonia to a Texture inside the Windows.UI.Composition tree.
+        /// This setting is true by default.
         /// </summary>
         /// <remarks>
         /// Supported on Windows 10 build 16299 and above. Ignored on other versions.
@@ -88,9 +86,19 @@ namespace Avalonia
         /// This is only recommended if low input latency is desirable, and there is no need for the transparency
         /// and stylings / blurrings offered by <see cref="UseWindowsUIComposition"/><br/>
         /// This is mutually exclusive with 
-        /// <see cref="UseWindowsUIComposition"/> which if active will override this setting. 
+        /// <see cref="UseWindowsUIComposition"/> which if active will override this setting.
+        /// This setting is false by default.
         /// </summary>
-        public bool UseLowLatencyDxgiSwapChain { get; set; } = false;
+        public bool UseLowLatencyDxgiSwapChain { get; set; }
+
+        /// <summary>
+        /// Render directly on the UI thread instead of using a dedicated render thread.
+        /// Only applicable if both <see cref="UseWindowsUIComposition"/> and <see cref="UseLowLatencyDxgiSwapChain"/>
+        /// are false.
+        /// This setting is only recommended for interop with systems that must render on the UI thread, such as WPF.
+        /// This setting is false by default.
+        /// </summary>
+        public bool ShouldRenderOnUIThread { get; set; }
         
         /// <summary>
         /// Provides a way to use a custom-implemented graphics context such as a custom ISkiaGpu
@@ -128,7 +136,7 @@ namespace Avalonia.Win32
 
         internal static bool UseOverlayPopups => Options.OverlayPopups;
         public static Win32PlatformOptions Options { get; private set; }
-        
+
         internal static Compositor Compositor { get; private set; }
 
         public static void Initialize()
@@ -139,6 +147,8 @@ namespace Avalonia.Win32
         public static void Initialize(Win32PlatformOptions options)
         {
             Options = options;
+            var renderTimer = options.ShouldRenderOnUIThread ? new UiThreadRenderTimer(60) : new DefaultRenderTimer(60);
+
             AvaloniaLocator.CurrentMutable
                 .Bind<IClipboard>().ToSingleton<ClipboardImpl>()
                 .Bind<ICursorFactory>().ToConstant(CursorFactory.Instance)
@@ -146,7 +156,7 @@ namespace Avalonia.Win32
                 .Bind<IPlatformSettings>().ToSingleton<Win32PlatformSettings>()
                 .Bind<IPlatformThreadingInterface>().ToConstant(s_instance)
                 .Bind<IRenderLoop>().ToConstant(new RenderLoop())
-                .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
+                .Bind<IRenderTimer>().ToConstant(renderTimer)
                 .Bind<IWindowingPlatform>().ToConstant(s_instance)
                 .Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control)
                 {