diff --git a/.gitignore b/.gitignore index 44fe5e4ba4..84faae1806 100644 --- a/.gitignore +++ b/.gitignore @@ -212,3 +212,6 @@ coc-settings.json *.map src/Web/Avalonia.Web.Blazor/wwwroot/*.js src/Web/Avalonia.Web.Blazor/Interop/Typescript/*.js +node_modules +src/Web/Avalonia.Web.Blazor/webapp/package-lock.json +src/Web/Avalonia.Web.Blazor/wwwroot diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 9fcb9d6b7f..4bbb667154 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -36,25 +36,6 @@ partial class Build : NukeBuild { [Solution("Avalonia.sln")] readonly Solution Solution; - static Lazy MsBuildExe = new Lazy(() => - { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return null; - - var msBuildDirectory = VSWhere("-latest -nologo -property installationPath -format value -prerelease").FirstOrDefault().Text; - - if (!string.IsNullOrWhiteSpace(msBuildDirectory)) - { - string msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\Current\Bin\MSBuild.exe"); - if (!System.IO.File.Exists(msBuildExe)) - msBuildExe = Path.Combine(msBuildDirectory, @"MSBuild\15.0\Bin\MSBuild.exe"); - - return msBuildExe; - } - - return null; - }, false); - BuildParameters Parameters { get; set; } protected override void OnBuildInitialized() { @@ -89,25 +70,28 @@ partial class Build : NukeBuild } ExecWait("dotnet version:", "dotnet", "--info"); ExecWait("dotnet workloads:", "dotnet", "workload list"); + Information("Processor count: " + Environment.ProcessorCount); + Information("Available RAM: " + GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 0x100000 + "MB"); } - IReadOnlyCollection MsBuildCommon( - string projectFile, - Configure configurator = null) + DotNetConfigHelper ApplySettingCore(DotNetConfigHelper c) { - return MSBuild(c => c - .SetProjectFile(projectFile) - // This is required for VS2019 image on Azure Pipelines - .When(Parameters.IsRunningOnWindows && - Parameters.IsRunningOnAzure, _ => _ - .AddProperty("JavaSdkDirectory", GetVariable("JAVA_HOME_11_X64"))) - .AddProperty("PackageVersion", Parameters.Version) + if (Parameters.IsRunningOnAzure) + c.AddProperty("JavaSdkDirectory", GetVariable("JAVA_HOME_11_X64")); + c.AddProperty("PackageVersion", Parameters.Version) .AddProperty("iOSRoslynPathHackRequired", true) - .SetProcessToolPath(MsBuildExe.Value) .SetConfiguration(Parameters.Configuration) - .SetVerbosity(MSBuildVerbosity.Minimal) - .Apply(configurator)); + .SetVerbosity(DotNetVerbosity.Minimal); + return c; } + DotNetBuildSettings ApplySetting(DotNetBuildSettings c, Configure configurator = null) => + ApplySettingCore(c).Build.Apply(configurator); + + DotNetPackSettings ApplySetting(DotNetPackSettings c, Configure configurator = null) => + ApplySettingCore(c).Pack.Apply(configurator); + + DotNetTestSettings ApplySetting(DotNetTestSettings c, Configure configurator = null) => + ApplySettingCore(c).Test.Apply(configurator); Target Clean => _ => _.Executes(() => { @@ -149,20 +133,11 @@ partial class Build : NukeBuild Target Compile => _ => _ .DependsOn(Clean, CompileNative) .DependsOn(CompileHtmlPreviewer) - .Executes(async () => + .Executes(() => { - if (Parameters.IsRunningOnWindows) - MsBuildCommon(Parameters.MSBuildSolution, c => c - .SetProcessArgumentConfigurator(a => a.Add("/r")) - .AddTargets("Build") - ); - - else - DotNetBuild(c => c - .SetProjectFile(Parameters.MSBuildSolution) - .AddProperty("PackageVersion", Parameters.Version) - .SetConfiguration(Parameters.Configuration) - ); + DotNetBuild(c => ApplySetting(c) + .SetProjectFile(Parameters.MSBuildSolution) + ); }); void RunCoreTest(string projectName) @@ -182,9 +157,8 @@ partial class Build : NukeBuild Information($"Running for {projectName} ({fw}) ..."); - DotNetTest(c => c + DotNetTest(c => ApplySetting(c) .SetProjectFile(project) - .SetConfiguration(Parameters.Configuration) .SetFramework(fw) .EnableNoBuild() .EnableNoRestore() @@ -263,19 +237,7 @@ partial class Build : NukeBuild .Executes(() => { var data = Parameters; - var pathToProjectSource = RootDirectory / "samples" / "ControlCatalog.NetCore"; - var pathToPublish = pathToProjectSource / "bin" / data.Configuration / "publish"; - - DotNetPublish(c => c - .SetProject(pathToProjectSource / "ControlCatalog.NetCore.csproj") - .EnableNoBuild() - .SetConfiguration(data.Configuration) - .AddProperty("PackageVersion", data.Version) - .AddProperty("PublishDir", pathToPublish)); - - Zip(data.ZipCoreArtifacts, data.BinRoot); Zip(data.ZipNuGetArtifacts, data.NugetRoot); - Zip(data.ZipTargetControlCatalogNetCoreDir, pathToPublish); }); Target CreateIntermediateNugetPackages => _ => _ @@ -283,15 +245,7 @@ partial class Build : NukeBuild .After(RunTests) .Executes(() => { - if (Parameters.IsRunningOnWindows) - - MsBuildCommon(Parameters.MSBuildSolution, c => c - .AddTargets("Pack")); - else - DotNetPack(c => c - .SetProject(Parameters.MSBuildSolution) - .SetConfiguration(Parameters.Configuration) - .AddProperty("PackageVersion", Parameters.Version)); + DotNetPack(c => ApplySetting(c).SetProject(Parameters.MSBuildSolution)); }); Target CreateNugetPackages => _ => _ diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index a92c988fbd..1826623674 100644 --- a/nukebuild/BuildParameters.cs +++ b/nukebuild/BuildParameters.cs @@ -51,14 +51,12 @@ public partial class Build public AbsolutePath NugetIntermediateRoot { get; } public AbsolutePath NugetRoot { get; } public AbsolutePath ZipRoot { get; } - public AbsolutePath BinRoot { get; } public AbsolutePath TestResultsRoot { get; } public string DirSuffix { get; } public List BuildDirs { get; } public string FileZipSuffix { get; } public AbsolutePath ZipCoreArtifacts { get; } public AbsolutePath ZipNuGetArtifacts { get; } - public AbsolutePath ZipTargetControlCatalogNetCoreDir { get; } public BuildParameters(Build b) @@ -121,14 +119,12 @@ public partial class Build NugetRoot = ArtifactsDir / "nuget"; NugetIntermediateRoot = RootDirectory / "build-intermediate" / "nuget"; ZipRoot = ArtifactsDir / "zip"; - BinRoot = ArtifactsDir / "bin"; TestResultsRoot = ArtifactsDir / "test-results"; BuildDirs = GlobDirectories(RootDirectory, "**bin").Concat(GlobDirectories(RootDirectory, "**obj")).ToList(); DirSuffix = Configuration; FileZipSuffix = Version + ".zip"; ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix); ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix); - ZipTargetControlCatalogNetCoreDir = ZipRoot / ("ControlCatalog.NetCore-" + FileZipSuffix); } string GetVersion() diff --git a/nukebuild/DotNetConfigHelper.cs b/nukebuild/DotNetConfigHelper.cs new file mode 100644 index 0000000000..932525288c --- /dev/null +++ b/nukebuild/DotNetConfigHelper.cs @@ -0,0 +1,57 @@ +using System.Globalization; +using JetBrains.Annotations; +using Nuke.Common.Tools.DotNet; +// ReSharper disable ReturnValueOfPureMethodIsNotUsed + +public class DotNetConfigHelper +{ + public DotNetBuildSettings Build; + public DotNetPackSettings Pack; + public DotNetTestSettings Test; + + public DotNetConfigHelper(DotNetBuildSettings s) + { + Build = s; + } + + public DotNetConfigHelper(DotNetPackSettings s) + { + Pack = s; + } + + public DotNetConfigHelper(DotNetTestSettings s) + { + Test = s; + } + + public DotNetConfigHelper AddProperty(string key, bool value) => + AddProperty(key, value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); + public DotNetConfigHelper AddProperty(string key, string value) + { + Build = Build?.AddProperty(key, value); + Pack = Pack?.AddProperty(key, value); + Test = Test?.AddProperty(key, value); + + return this; + } + + public DotNetConfigHelper SetConfiguration(string configuration) + { + Build = Build?.SetConfiguration(configuration); + Pack = Pack?.SetConfiguration(configuration); + Test = Test?.SetConfiguration(configuration); + return this; + } + + public DotNetConfigHelper SetVerbosity(DotNetVerbosity verbosity) + { + Build = Build?.SetVerbosity(verbosity); + Pack = Pack?.SetVerbostiy(verbosity); + Test = Test?.SetVerbosity(verbosity); + return this; + } + + public static implicit operator DotNetConfigHelper(DotNetBuildSettings s) => new DotNetConfigHelper(s); + public static implicit operator DotNetConfigHelper(DotNetPackSettings s) => new DotNetConfigHelper(s); + public static implicit operator DotNetConfigHelper(DotNetTestSettings s) => new DotNetConfigHelper(s); +} \ No newline at end of file diff --git a/samples/ControlCatalog/Converter/HexConverter.cs b/samples/ControlCatalog/Converter/HexConverter.cs new file mode 100644 index 0000000000..31cce5ba67 --- /dev/null +++ b/samples/ControlCatalog/Converter/HexConverter.cs @@ -0,0 +1,34 @@ +using System; +using System.Globalization; +using Avalonia; +using Avalonia.Data.Converters; + +namespace ControlCatalog.Converter; + +public class HexConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + var str = value?.ToString(); + if (str == null) + return AvaloniaProperty.UnsetValue; + if (int.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int x)) + return (decimal)x; + return AvaloniaProperty.UnsetValue; + + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + try + { + if (value is decimal d) + return ((int)d).ToString("X8"); + return AvaloniaProperty.UnsetValue; + } + catch + { + return AvaloniaProperty.UnsetValue; + } + } +} diff --git a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml index 1f4d1e6018..045ba4a059 100644 --- a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml +++ b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml @@ -1,6 +1,7 @@  @@ -97,6 +98,17 @@ + + + + + + + + + + diff --git a/src/Avalonia.Base/Layout/LayoutHelper.cs b/src/Avalonia.Base/Layout/LayoutHelper.cs index 404d19906a..0851dbaea9 100644 --- a/src/Avalonia.Base/Layout/LayoutHelper.cs +++ b/src/Avalonia.Base/Layout/LayoutHelper.cs @@ -251,6 +251,17 @@ namespace Avalonia.Layout { double newValue; + // Round the value to avoid FP errors. This is needed because if `value` has a floating + // point precision error (e.g. 79.333333333333343) then when it's multiplied by + // `dpiScale` and rounded up, it will be rounded up to a value one greater than it + // should be. +#if NET6_0_OR_GREATER + value = Math.Round(value, 8, MidpointRounding.ToZero); +#else + // MidpointRounding.ToZero isn't available in netstandard2.0. + value = Math.Truncate(value * 1e8) / 1e8; +#endif + // If DPI == 1, don't use DPI-aware rounding. if (!MathUtilities.IsOne(dpiScale)) { diff --git a/src/Avalonia.Base/Media/DashStyle.cs b/src/Avalonia.Base/Media/DashStyle.cs index abee580020..3a30b2d32f 100644 --- a/src/Avalonia.Base/Media/DashStyle.cs +++ b/src/Avalonia.Base/Media/DashStyle.cs @@ -35,7 +35,6 @@ namespace Avalonia.Media /// Initializes a new instance of the class. /// public DashStyle() - : this(null, 0) { } diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs index 9aa3c25425..e47c8e7e31 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs @@ -29,6 +29,7 @@ public class CompositingRenderer : IRendererWithCompositor private bool _queuedUpdate; private Action _update; private Action _invalidateScene; + private bool _updating; internal CompositionTarget CompositionTarget; @@ -77,6 +78,8 @@ public class CompositingRenderer : IRendererWithCompositor /// public void AddDirty(IVisual visual) { + if (_updating) + throw new InvalidOperationException("Visual was invalidated during the render pass"); _dirty.Add((Visual)visual); QueueUpdate(); } @@ -84,7 +87,16 @@ public class CompositingRenderer : IRendererWithCompositor /// public IEnumerable HitTest(Point p, IVisual root, Func? filter) { - var res = CompositionTarget.TryHitTest(p, filter); + Func? f = null; + if (filter != null) + f = v => + { + if (v is CompositionDrawListVisual dlv) + return filter(dlv.Visual); + return true; + }; + + var res = CompositionTarget.TryHitTest(p, f); if(res == null) yield break; foreach(var v in res) @@ -107,6 +119,8 @@ public class CompositingRenderer : IRendererWithCompositor /// public void RecalculateChildren(IVisual visual) { + if (_updating) + throw new InvalidOperationException("Visual was invalidated during the render pass"); _recalculateChildren.Add((Visual)visual); QueueUpdate(); } @@ -191,7 +205,7 @@ public class CompositingRenderer : IRendererWithCompositor private void InvalidateScene() => SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs(_root, new Rect(_root.ClientSize))); - private void Update() + private void UpdateCore() { _queuedUpdate = false; foreach (var visual in _dirty) @@ -240,6 +254,21 @@ public class CompositingRenderer : IRendererWithCompositor CompositionTarget.Scaling = _root.RenderScaling; Compositor.InvokeOnNextCommit(_invalidateScene); } + + private void Update() + { + if(_updating) + return; + _updating = true; + try + { + UpdateCore(); + } + finally + { + _updating = false; + } + } public void Resized(Size size) { diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs index 77b392eee5..b019d1792b 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs @@ -54,13 +54,11 @@ internal class CompositionDrawListVisual : CompositionContainerVisual Visual = visual; } - internal override bool HitTest(Point pt, Func? filter) + internal override bool HitTest(Point pt) { var custom = Visual as ICustomHitTest; if (DrawList == null && custom == null) return false; - if (filter != null && !filter(Visual)) - return false; if (custom != null) { // Simulate the old behavior diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs index 4e53e163ec..eb499604e0 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs @@ -31,7 +31,7 @@ namespace Avalonia.Rendering.Composition /// /// /// - public PooledList? TryHitTest(Point point, Func? filter) + public PooledList? TryHitTest(Point point, Func? filter) { Server.Readback.NextRead(); if (Root == null) @@ -88,10 +88,14 @@ namespace Avalonia.Rendering.Composition } void HitTestCore(CompositionVisual visual, Point globalPoint, PooledList result, - Func? filter) + Func? filter) { if (visual.Visible == false) return; + + if (filter != null && !filter(visual)) + return; + if (!TryTransformTo(visual, globalPoint, out var point)) return; @@ -111,7 +115,7 @@ namespace Avalonia.Rendering.Composition } // Hit-test the current node - if (visual.HitTest(point, filter)) + if (visual.HitTest(point)) result.Add(visual); } diff --git a/src/Avalonia.Base/Rendering/Composition/Visual.cs b/src/Avalonia.Base/Rendering/Composition/Visual.cs index 7356b7b9e8..6d6818256a 100644 --- a/src/Avalonia.Base/Rendering/Composition/Visual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Visual.cs @@ -53,6 +53,6 @@ namespace Avalonia.Rendering.Composition internal object? Tag { get; set; } - internal virtual bool HitTest(Point point, Func? filter) => true; + internal virtual bool HitTest(Point point) => true; } } diff --git a/src/Avalonia.Base/Rendering/DirtyVisuals.cs b/src/Avalonia.Base/Rendering/DirtyVisuals.cs index 00bc236b9c..999b12e810 100644 --- a/src/Avalonia.Base/Rendering/DirtyVisuals.cs +++ b/src/Avalonia.Base/Rendering/DirtyVisuals.cs @@ -17,8 +17,7 @@ namespace Avalonia.Rendering { private SortedDictionary> _inner = new SortedDictionary>(); private Dictionary _index = new Dictionary(); - private List _deferredChanges = new List(); - private int _deferring; + private int _enumerating; /// /// Gets the number of dirty visuals. @@ -31,10 +30,9 @@ namespace Avalonia.Rendering /// The dirty visual. public void Add(IVisual visual) { - if (_deferring > 0) + if (_enumerating > 0) { - _deferredChanges.Add(visual); - return; + throw new InvalidOperationException("Visual was invalidated during a render pass"); } var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot); @@ -65,7 +63,7 @@ namespace Avalonia.Rendering /// public void Clear() { - if (_deferring > 0) + if (_enumerating > 0) { throw new InvalidOperationException("Cannot clear while enumerating"); } @@ -80,7 +78,7 @@ namespace Avalonia.Rendering /// A collection of visuals. public IEnumerator GetEnumerator() { - BeginDefer(); + _enumerating++; try { foreach (var i in _inner) @@ -93,27 +91,10 @@ namespace Avalonia.Rendering } finally { - EndDefer(); + _enumerating--; } } - - private void BeginDefer() - { - ++_deferring; - } - - private void EndDefer() - { - if (--_deferring > 0) return; - - foreach (var visual in _deferredChanges) - { - Add(visual); - } - - _deferredChanges.Clear(); - } - + /// /// Gets the dirty visuals, in ascending order of distance to their root. /// diff --git a/src/Avalonia.Controls.ColorPicker/Converters/DoNothingForNullConverter.cs b/src/Avalonia.Controls.ColorPicker/Converters/DoNothingForNullConverter.cs new file mode 100644 index 0000000000..421a5acb28 --- /dev/null +++ b/src/Avalonia.Controls.ColorPicker/Converters/DoNothingForNullConverter.cs @@ -0,0 +1,35 @@ +using System; +using System.Globalization; +using Avalonia.Data; +using Avalonia.Data.Converters; + +namespace Avalonia.Controls.Converters +{ + /// + /// Converter that will do nothing (not update bound values) when a null value is encountered. + /// This converter enables binding nullable with non-nullable properties in some scenarios. + /// + public class DoNothingForNullConverter : IValueConverter + { + /// + public object? Convert( + object? value, + Type targetType, + object? parameter, + CultureInfo culture) + { + return value ?? BindingOperations.DoNothing; + } + + /// + public object? ConvertBack( + object? value, + Type targetType, + object? parameter, + CultureInfo culture) + { + return value ?? BindingOperations.DoNothing; + } + } +} + diff --git a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml index 59cc48975f..dab4142001 100644 --- a/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml +++ b/src/Avalonia.Controls.ColorPicker/Themes/Fluent/ColorView.xaml @@ -11,6 +11,7 @@ + 48 30 @@ -205,7 +206,7 @@ diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml index 733b3c19c9..b4bae02b9b 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml @@ -53,7 +53,6 @@ - diff --git a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml index 6eb62bcd33..0cfd491b21 100644 --- a/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/DatePicker.xaml @@ -56,18 +56,11 @@ - - diff --git a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml index a23744b15c..fcd661a4b5 100644 --- a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml @@ -55,18 +55,11 @@ - - diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs index 8688671d3b..b64423ec10 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs @@ -7,6 +7,7 @@ using Avalonia.LinuxFramebuffer.Input; using Avalonia.LinuxFramebuffer.Output; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.Rendering.Composition; namespace Avalonia.LinuxFramebuffer { @@ -32,7 +33,7 @@ namespace Avalonia.LinuxFramebuffer { var factory = AvaloniaLocator.Current.GetService(); var renderLoop = AvaloniaLocator.Current.GetService(); - return factory?.Create(root, renderLoop) ?? new DeferredRenderer(root, renderLoop); + return factory?.Create(root, renderLoop) ?? new CompositingRenderer(root, LinuxFramebufferPlatform.Compositor); } public void Dispose() diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index a642766809..bf9452e191 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -15,6 +15,7 @@ using Avalonia.LinuxFramebuffer.Output; using Avalonia.OpenGL; using Avalonia.Platform; using Avalonia.Rendering; +using Avalonia.Rendering.Composition; using Avalonia.Threading; using JetBrains.Annotations; @@ -26,6 +27,10 @@ namespace Avalonia.LinuxFramebuffer private static readonly Stopwatch St = Stopwatch.StartNew(); internal static uint Timestamp => (uint)St.ElapsedTicks; public static InternalPlatformThreadingInterface Threading; + + internal static Compositor Compositor { get; private set; } + + LinuxFramebufferPlatform(IOutputBackend backend) { _fb = backend; @@ -48,6 +53,10 @@ namespace Avalonia.LinuxFramebuffer .Bind().ToConstant(new KeyboardDevice()) .Bind().ToSingleton() .Bind().ToSingleton(); + + Compositor = new Compositor( + AvaloniaLocator.Current.GetRequiredService(), + AvaloniaLocator.Current.GetService()); } diff --git a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj index 1531c95830..3fcfaa1c9c 100644 --- a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj +++ b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj @@ -8,31 +8,16 @@ false true - + - - wwwroot - true - true - - - - false - true - - - true - false - - - + true @@ -45,12 +30,26 @@ + + - + + + + + + + + + + + + + diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor index b501db16d3..27a6acd0de 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor @@ -1,7 +1,11 @@ -
+ oncut="return false;" + @onkeydown:preventDefault="true" + @onkeyup:preventDefault="true" + autocapitalize="none"/>