You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a simple but yet stunning sample, so we want to show it.
Description
The problem is very strange for me, I have never encountered this before, and, to be honest, I am not entirely sure what exactly the problem is, in my code, in Avalonia, in .NET Core, or maybe in the debugger. Or maybe not a problem at all, but an inevitable behavior when using a debugger and breakpoints.
When I add my custom control to Window (this control uses Render), and then execute an asynchronous command in the WindowViewModel that awaits something longer than ~2 seconds (and has a breakpoint on it), and after that it also executes some code, then when the code of this command is completed, the application freezes completely and then crashes.
Steps to reproduce the behavior
Create a new Avalonia MVVM app project on .NET Core 8 (Avalonia version 11.0.6)
Add a custom SnowfallControl to the project with the following code:
public class SnowfallControl : Control
{
private readonly List<Snowflake> snowflakes = [];
private readonly DispatcherTimer timer = new();
private readonly Stopwatch stopwatch = new();
public SnowfallControl()
{
Loaded += (_, _) =>
{
// Initialize snowflakes
for (var i = 0; i < 200; i++)
{
snowflakes.Add(new Snowflake
{
Position = new Point(Random.Shared.NextDouble() * Bounds.Width, Random.Shared.NextDouble() * Bounds.Height),
Speed = Random.Shared.NextDouble() * 40 + 20,
Size = Random.Shared.NextDouble() * 2 + 1
});
}
timer.Interval = TimeSpan.FromMilliseconds(1000.0 / 60.0); // 60 FPS
timer.Tick += (_, _) => InvalidateVisual();
timer.Start();
stopwatch.Start();
};
}
public override void Render(DrawingContext context)
{
base.Render(context);
// Calculate elapsed time since last frame
var elapsedTime = stopwatch.Elapsed.TotalSeconds;
stopwatch.Restart();
// Update and draw snowflakes
foreach (var snowflake in snowflakes)
{
snowflake.Position = new Point(snowflake.Position.X, snowflake.Position.Y + snowflake.Speed * elapsedTime);
if (snowflake.Position.Y > Bounds.Height)
{
snowflake.Position = new Point(Random.Shared.NextDouble() * Bounds.Width, 0);
}
context.DrawRectangle(Brushes.White, null, new Rect(snowflake.Position.X, snowflake.Position.Y, snowflake.Size, snowflake.Size));
}
}
}
public class Snowflake
{
public Point Position { get; set; }
public double Speed { get; set; }
public double Size { get; set; }
}
Add this control to MainWindow.axaml:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:AvaloniaCustomControlRenderBugReproduction.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:AvaloniaCustomControlRenderBugReproduction.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AvaloniaCustomControlRenderBugReproduction.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="AvaloniaCustomControlRenderBugReproduction">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<Grid>
<StackPanel>
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button Command="{Binding DoSomethingCommand}" Content="Test"/>
</StackPanel>
<controls:SnowfallControl IsHitTestVisible="False"/>
</Grid>
</Window>
Change the MainWindowViewModel code to the following:
public class MainWindowViewModel : ViewModelBase
{
#pragma warning disable CA1822 // Mark members as static
private string greeting = "Welcome to Avalonia!";
public string Greeting
{
get => greeting;
set => this.RaiseAndSetIfChanged(ref greeting, value);
}
public ReactiveCommand<Unit, Unit> DoSomethingCommand { get; init; }
public MainWindowViewModel()
{
DoSomethingCommand = ReactiveCommand.CreateFromTask(DoSomething);
}
private async Task DoSomething()
{
await Task.Delay(5000);
//No matter what code will be executed after awaiting, the issue happens
var test1 = "Test1";
var test2 = "Test2";
var test3 = test1 += test2;
//Greeting = "Delay awaited";
}
#pragma warning restore CA1822 // Mark members as static
}
Set a breakpoint at await Task.Delay(5000)
Run the program in debug mode
When debugging stops at await Task.Delay(5000), do Step Over, and then Resume Program.
After this, the application will freeze for a while and crash with the following error:
Fatal error. Internal CLR error. (0x80131506)
at Avalonia.Rendering.Composition.Drawing.RenderDataDrawingContext.DrawRectangleCore(Avalonia.Media.IBrush, Avalonia.Media.IPen, Avalonia.RoundedRect, Avalonia.Media.BoxShadows)
at Avalonia.Media.DrawingContext.DrawRectangle(Avalonia.Media.IBrush, Avalonia.Media.IPen, Avalonia.Rect, Double, Double, Avalonia.Media.BoxShadows)
at AvaloniaCustomControlRenderBugReproduction.Controls.SnowfallControl.Render(Avalonia.Media.DrawingContext)
at Avalonia.Rendering.Composition.CompositingRenderer.UpdateCore()
at Avalonia.Rendering.Composition.CompositingRenderer.Update()
at Avalonia.Rendering.Composition.Compositor.CommitCore()
at Avalonia.Rendering.Composition.Compositor.Commit()
at Avalonia.Media.MediaContext.CommitCompositor(Avalonia.Rendering.Composition.Compositor)
at Avalonia.Media.MediaContext.CommitCompositorsWithThrottling()
at Avalonia.Media.MediaContext.RenderCore()
at Avalonia.Media.MediaContext.Render()
at Avalonia.Threading.DispatcherOperation.InvokeCore()
at Avalonia.Threading.DispatcherOperation.Execute()
at Avalonia.Threading.Dispatcher.ExecuteJob(Avalonia.Threading.DispatcherOperation)
at Avalonia.Threading.Dispatcher.ExecuteJobsCore(Boolean)
at Avalonia.Threading.Dispatcher.Signaled()
at Avalonia.Win32.Win32DispatcherImpl.DispatchWorkItem()
at Avalonia.Win32.Win32Platform.WndProc(IntPtr, UInt32, IntPtr, IntPtr)
at Avalonia.Win32.Interop.UnmanagedMethods.DispatchMessage(MSG ByRef)
at Avalonia.Win32.Interop.UnmanagedMethods.DispatchMessage(MSG ByRef)
at Avalonia.Win32.Win32DispatcherImpl.RunLoop(System.Threading.CancellationToken)
at Avalonia.Threading.DispatcherFrame.Run(Avalonia.Threading.IControlledDispatcherImpl)
at Avalonia.Threading.Dispatcher.PushFrame(Avalonia.Threading.DispatcherFrame)
at Avalonia.Threading.Dispatcher.MainLoop(System.Threading.CancellationToken)
at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(System.String[])
at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime(Avalonia.AppBuilder, System.String[], Avalonia.Controls.ShutdownMode)
at AvaloniaCustomControlRenderBugReproduction.Program.Main(System.String[])
When the program crashes, the IDE also displays the following message: Target process has exited during evaluation of instance method System.Exception::get_Message() with actual parameters System.ExecutionEngineException. This may possibly happen due to StackOverflowException.
The problem does not arise in production if the program is executed without debugging. The problem also does not arise even if the program is launched in debugging mode but there is no breakpoint on await.
GPU interop - hardcore approach, the best for low level rendering with direct access to OpenGL/D3D/Vulkan. Should be ideal for media players or game integrations. GpuInteropOpenGl
We have samples for all of these approaches randomly scattered across our repositories. At the very least this comment should help with googling them. Ideally, yes, these should be duplicated here.
On how to force next rendered frame (Dispatcher + InvalidateVisual in 0.10, and Window.RequestAnimationFrame in 11.0)
On how to render text efficiently (can be yet another series of samples, as there are many approaches again)
This is a simple but yet stunning sample, so we want to show it.
Description
The problem is very strange for me, I have never encountered this before, and, to be honest, I am not entirely sure what exactly the problem is, in my code, in Avalonia, in .NET Core, or maybe in the debugger. Or maybe not a problem at all, but an inevitable behavior when using a debugger and breakpoints.
When I add my custom control to Window (this control uses Render), and then execute an asynchronous command in the WindowViewModel that awaits something longer than ~2 seconds (and has a breakpoint on it), and after that it also executes some code, then when the code of this command is completed, the application freezes completely and then crashes.
Steps to reproduce the behavior
await Task.Delay(5000)
When the program crashes, the IDE also displays the following message:
Target process has exited during evaluation of instance method System.Exception::get_Message() with actual parameters System.ExecutionEngineException. This may possibly happen due to StackOverflowException.
Issue reproduction video
Environment
Additional context
The problem does not arise in production if the program is executed without debugging. The problem also does not arise even if the program is launched in debugging mode but there is no breakpoint on await.
Originally posted by @BnnQ in AvaloniaUI/Avalonia#14144
The text was updated successfully, but these errors were encountered: