Как рисовать на холсте в авалонии?

Я изучаю Avalonia для небольшого проекта, и мне это очень нравится, но я не могу найти много документации по рисованию на холсте.

Моя цель очень проста: нарисовать сетку на холсте...

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

Я создал этот пример, чтобы проиллюстрировать:

public partial class Tests : UserControl, IInterface
{

    private double gridSize = 2;
    private SolidColorBrush gridBrush = new SolidColorBrush(Colors.Black);

    public Tests()
    {
        InitializeComponent();
        gridCanvas.InvalidateVisual();
    }

    public override void Render(DrawingContext context)
    {
        base.Render(context);
        DrawGrid(context);
    }

    private void DrawGrid(DrawingContext context)
    {
        var canvasWidth = gridCanvas.Bounds.Width;
        var canvasHeight = gridCanvas.Bounds.Height;

        var pen = new Pen(Brushes.Black, thickness: 20); // Adjust thickness if necessary

        for (double x = 0; x < canvasWidth; x += gridSize)
        {
            context.DrawLine(pen, new Point(x, 0), new Point(x, canvasHeight));
        }

        for (double y = 0; y < canvasHeight; y += gridSize)
        {
            context.DrawLine(pen, new Point(0, y), new Point(canvasWidth, y));
        }
    }
}
<UserControl xmlns = "https://github.com/avaloniaui"
             xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable = "d" d:DesignWidth = "800" d:DesignHeight = "450"
             x:Class = "AvaloniaTest.Tests">

    <Canvas Name = "gridCanvas" Background = "Beige">
        <Rectangle Fill = "Red" Canvas.Left = "10" Canvas.Top = "10" Width = "5" Height = "5"/>
    </Canvas>
    
</UserControl>

В этом примере я вижу красный прямоугольник в верхнем левом углу и бежевый фон, но не сетку. Может кто-нибудь объяснить, почему?

Заранее спасибо и хорошего дня.

Вероятно, это связано с тем, что вы выполняете рендеринг в DrawingContext UserControl, а не в Canvas. Вам следует создать экземпляр класса Line и добавить его на холст canvas.Children.Add(line);. Canvas будет обрабатывать события рисования и рисовать всех своих детей. Таким образом, вам не придется рисовать их в событии рисования.

Jeroen van Langen 29.08.2024 19:25

Сначала я рассматривал возможность использования элементов Rectangle (потому что это большие линии, верно?), но поскольку мне может понадобиться их много, и они статичны, я думаю, что с линиями может возникнуть та же проблема.

Zartox29 29.08.2024 21:37
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как упоминал Йерун ван Ланген, ваша проблема в том, что вы рисуете в контексте рисования UserControl. Вы можете использовать линии и добавить их на холст.

Line line = new()
{
  // Setup.
};
gridCanvas.Children.Add(line);

Однако помните, что линия — это фигура (Avalonia.Controls.Shapes). Фигуры являются элементами управления, то есть они наследуют Control. Это означает, что у них есть много накладных расходов, которые вам могут не понадобиться, чтобы позволить им функционировать в качестве элемента управления. Это нормально, если вам нужны функции управления, такие как возможность их динамического перемещения, но если все, что вам нужно, это статический рисунок и особенно если в противном случае вам понадобится большое количество фигур, это может потребовать больших затрат ресурсов.

Однако вы можете визуализировать DrawingContext в элементе управления (или в любом визуальном элементе, где рендеринг не запечатан). К сожалению, у нас нет опции DrawingVisual.RenderOpen, такой как WPF, для захвата DrawingContext. Вместо этого вам придется создать класс, производный от Control, и переопределить Render для этого объекта.

public class DrawingCanvas : Control
{
  // Constructors and stuff

  public override void Render(DrawingContext context)
  {
    base.Render(context);
    // Draw here.
  }
}

Вам также может потребоваться вызвать InvalidateVisual() для рендеринга.

Чтобы включить это в свое представление, просто добавьте локальное пространство имен:

xmlns:local = "clr-namespace=AvaloniaTest"

И добавьте предисловие к имени в xaml:

<local:DrawingCanvas/>

Да, я думаю, что строки - это не то, что мне нужно, к сожалению. Но вторая часть, кажется, то, что мне нужно. Но я создал класс, производный от Canvas, но он помечен как запечатанный, я что-то пропустил?

Zartox29 29.08.2024 21:45

@Zartox29 Zartox29 Вы абсолютно правы, хорошая новость в том, что вам не нужен Canvas, поэтому вместо этого наследуйте Control. Я обновил свой ответ.

Tarazed 29.08.2024 21:58

Это именно то, что мне было нужно, спасибо.

Zartox29 30.08.2024 02:12

Другие вопросы по теме

Авалония – изменение DataTemplate на основе значений коллекции вызывает исключение ArgumentOutOfRangeException
Как отобразить диалоговое окно (Вход) перед MainWindow в Авалонии?
Добавление кнопки в представление, которая перенаправляет пользователя в другое представление в Авалонии с помощью Community Toolkit и MVVM
Ошибка Avalonia AVLN: 0004: невозможно разрешить свойство или метод с именем «Test» для типа «Avalonia_Blog.Models.Post»
ProgressBar не обновляется при изменении значения в методе OnLoaded
Как привязать ListBoxItem.IsSelected к свойству в ViewModel?
Запуск приложения Android через действие с фильтром намерений приводит к изменению значка и названию приложения как «Сервисы Google Play»
Авалония, как предотвратить обновление текстового поля при каждом нажатии клавиши?
Инструментарий сообщества MVVM, обеспечивающий синхронизацию двух представлений с одной моделью в приложении Avalonia
Зависание окна сообщений пользовательского интерфейса Avalonia