Xamarin.Mac NSView DrawRect не вызывается несмотря на NeedsDisplay - PullRequest
0 голосов
/ 19 июня 2019

Я пытаюсь создать вид, представляющий вертикальную линию, которая перемещается горизонтально внутри другого вида.

У меня есть следующий ViewController и пользовательский вид.

using System;
using System.Timers;
using AppKit;
using CoreGraphics;

namespace CustomControlExperiment
{
    public partial class ViewController : NSViewController
    {
        private Timer _timer;
        private LineControl _lineControl;

        public ViewController(IntPtr handle) : base(handle)
        {
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            var frame = new CGRect { X = 0, Y = 0, Height = ContentView.Frame.Height, Width = 1 };
            _lineControl = new LineControl(frame);

            ContentView.AddSubview(_lineControl);

            _timer = new Timer(500);
            _timer.Elapsed += _timer_Elapsed;
            _timer.Start();

        }

        private void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _lineControl.Position++;
        }
    }

    public class LineControl : NSView
    {
        private float _position;

        public LineControl(CGRect frameRect) : base(frameRect)
        {
            Initialize();
        }

        private void Initialize()
        {
            WantsLayer = true;
        }

        public override void DrawRect(CGRect dirtyRect)
        {
            Console.WriteLine("DrawRect");
            base.DrawRect(dirtyRect);

            var context = NSGraphicsContext.CurrentContext?.CGContext;

            if (context == null)
            {
                return;
            }

            var height = Frame.Height;

            context.SetStrokeColor(new CGColor(.5f, .6f, .7f));
            context.SetLineWidth(1f);
            context.SetLineDash(0, new nfloat[] { 3, 3 });

            context.MoveTo(0, 0);
            context.AddLineToPoint(0, height);

            context.StrokePath();
        }

        public float Position
        {
            get => _position;
            set
            {
                _position = value;
                Console.WriteLine("Position = " + _position);

                NeedsDisplay = true;
            }
        }
    }
}

DrawRect вызывается один раз при первом запуске программы.После этого он не вызывается снова, несмотря на увеличение позиции и установку NeedsDisplay.

Что я делаю не так?

1 Ответ

1 голос
/ 20 июня 2019

Событие System.Timers.Timer elapsed запускается в потоке пула потоков - недопустимо устанавливать needsDisplay вне основного потока. Если вы попробуете это в XCode, это ошибка времени выполнения из средства очистки потока.

Вам необходимо изменить код, чтобы Position обновлялся из основного потока, или перенаправить вызов для установки needsDisplay в основной поток.

Существуют различные подходы к этому в .NET и Xamarin - здесь - это один документ, предлагающий использовать InvokeOnMainThread (это для iOS, но я считаю, что это применимо и к macOS).

...