简体   繁体   English

在SKCanvas中进行绘制时,C#:AccessViolationException

[英]C#: AccessViolationException when drawing in SKCanvas

Introduction 介绍

I am creating my first Xamarin app (that will target UWP first, then Android, finally maybe iOS). 我正在创建我的第一个Xamarin应用程序(它将首先针对UWP,然后针对Android,最后可能针对iOS)。

Basically, the app should detect multiple fingers and circles will pop over each finger and follow them. 基本上,该应用应检测到多个手指,并且圆圈将在每个手指上弹出并跟随它们。

The problem 问题

I am having an System.AccessViolationException when trying to draw on a staic SKCanvas on my onPanning method from MR.gestures . 尝试从MR.gestures的 onPanning方法上使用静态SKCanvas时遇到System.AccessViolationException

Screenshot 屏幕截图

UWP app和Visual Studio 2017上的AccessViolationException

Details 细节

L'exception System.AccessViolationException s'est produite System.AccessViolationException的最大产品
HResult=0x80004003 Message=Attempted to read or write protected memory. HResult = 0x80004003 Message =尝试读取或写入受保护的内存。 This is often an indication that other memory is corrupt. 这通常表明其他内存已损坏。
Source= Arborescence des appels de procédure : à SkiaSharp.SkiaApi.sk_canvas_draw_circle(IntPtr t, Single cx, Single cy, Single radius, IntPtr paint) à SkiaSharp.SKCanvas.DrawCircle(Single cx, Single cy, Single radius, SKPaint paint) à App1.MainPage.drawCircleOnCanvas(Point pointerPos, Int32 radius) dans d:\\Profiles\\qpollet\\Documents\\Visual Studio 2017\\Projects\\App1\\App1\\App1\\MainPage.xaml.cs :ligne 70 à App1.MainPage.onPanning(Object sender, PanEventArgs e) dans d:\\Profiles\\qpollet\\Documents\\Visual Studio 2017\\Projects\\App1\\App1\\App1\\MainPage.xaml.cs :ligne 54 à MR.Gestures.GestureHandler.<>c__DisplayClass115_0`1.b__0() à Xamarin.Forms.Platform.UWP.WindowsBasePlatformServices.<>c__DisplayClass2_0.b__0() 来源=应用程序树状结构:àSkiaSharp.SkiaApi.sk_canvas_draw_circle(IntPtr t,Single cx,Single cy,Single radius,IntPtr paint)àSkiaSharp.SKCanvas.DrawCircle(Single cx,Single cy,Single radius,SKPaint paint)à App1.MainPage.drawCircleOnCanvas(PointpointerPos,Int32半径)dans d:\\ Profiles \\ qpollet \\ Documents \\ Visual Studio 2017 \\ Projects \\ App1 \\ App1 \\ App1 \\ MainPage.xaml.cs:ligne 70àApp1.MainPage.onPanning(Object发送者PanEventArgs e)dans d:\\ Profiles \\ qpollet \\ Documents \\ Visual Studio 2017 \\ Projects \\ App1 \\ App1 \\ App1 \\ MainPage.xaml.cs:ligne 54àMR.Gestures.GestureHandler。<> c__DisplayClass115_0`1.b__0( )Xamarin.Forms.Platform.UWP.WindowsBasePlatformServices。<> c__DisplayClass2_0.b__0()

The code 编码

MainPage.xaml.cs MainPage.xaml.cs

using SkiaSharp;
using SkiaSharp.Views.Forms;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using MR.Gestures;

namespace App1
{
    public partial class MainPage : Xamarin.Forms.ContentPage
    {
        private static SKCanvas canvas;

        public MainPage()
        {
            InitializeComponent();
        }

        private void OnPainting(object sender, SKPaintSurfaceEventArgs e)
        {
            canvas = e.Surface.Canvas;

            Point pointerPos = new Point
            {
                X = 200,
                Y = 400
            };
            drawCircleOnCanvas(pointerPos, 50);

            Point pointerPos1 = new Point
            {
                X = 1000,
                Y = 600
            };
            drawCircleOnCanvas(pointerPos1, 50);
        }

        private void onPanning(object sender, PanEventArgs e)
        {
            Debug.WriteLine("MR Panning !!!!!");

            try
            {
                List<Point> touches = e.Touches.ToList();
                //foreach (Point touch in touches)
                for(int i = 0; i <= touches.Count; i++)
                {
                    Point touch = touches[i];
                    Debug.WriteLine("index " + i + " : " + touch.X + " " + touch.Y);
                    drawCircleOnCanvas(touch, 50);
                }
            }
            catch (ArgumentNullException) { }
        }

        internal void drawCircleOnCanvas(Point pointerPos, int radius)
        {
            Debug.WriteLine(pointerPos.X + " " + pointerPos.Y);

            SKPaint circleFill = new SKPaint
            {
                IsAntialias = true,
                Style = SKPaintStyle.Fill,
                Color = SKColors.Red
            };
            canvas.DrawCircle(((float) pointerPos.X - radius), ((float) pointerPos.Y - radius), radius, circleFill);
        }
    }
}

MainPage.xaml MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:App1"
             xmlns:views="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             xmlns:mr="clr-namespace:MR.Gestures;assembly=MR.Gestures"
             x:Class="App1.MainPage">

    <Label Text="Ooooh, you touch my tralala" 
           VerticalOptions="Center" 
           HorizontalOptions="Center" />

    <RelativeLayout>

        <mr:AbsoluteLayout
            RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}"
            RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}"
            RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width}"
            RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height}"

            BackgroundColor="Blue"

            x:Name="touchLayout"
            Panning="onPanning">

        </mr:AbsoluteLayout>

        <views:SKCanvasView
            RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}"
            RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=0}"
            RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width}"
            RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height}"

            PaintSurface="OnPainting"/>

    </RelativeLayout>
</ContentPage>

Result 结果 Windows 10模拟器上的Xamarin SKCanvas屏幕截图

Any idea ? 任何想法 ?

You will get that error because you are saving the canvas. 您将收到该错误,因为您正在保存画布。 The canvas is recreated on each frame render, so you cannot keep a handle to it. 在每个帧渲染上都会重新创建画布,因此您无法保留其手柄。

The correct way is to only ever reference the canvas INSIDE the paint method. 正确的方法是仅在paint方法内部引用画布。 Then, in your padding method, just invalidate the surface using InvalidateSurface . 然后,在填充方法中,只需使用InvalidateSurface使表面InvalidateSurface

This will trigger a redraw, and then you can draw the items in new locations. 这将触发重新绘制,然后您可以在新位置绘制项目。

class MainPage {
    List<Point> touches;
    void onPan() {
        touches = GetTouchPoints();
        view.InvalidateSurface();
    }
    void onPaint() {
        var canvas = ...;
        canvas.Draw(...);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM