Как я могу программно установить геометрию пути с помощью C++/WinRT + WinUI 3

После десятилетий написания приложений MFC я пытаюсь изучить C++/WinRT и WinUI 3. Для этого я работаю над 6-м изданием Петцольда «Программирование Windows», преобразуя код из C# в C++/WinRT. Я в главе 2 работаю над примером PathMarkupSyntaxCode. Вот код С#:

        public MainPage()
        {
            this.InitializeComponent();

            Path path = new Path
            {
                Stroke = new SolidColorBrush(Colors.Red),
                StrokeThickness = 12,
                StrokeLineJoin = PenLineJoin.Round,
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment =  VerticalAlignment.Center,
                Data = PathMarkupToGeometry(
                    "M 0 0 L 0 100 M 0 50 L 50 50 M 50 0 L 50 100 " +
                    "M 125 0 C 60 -10, 60 60, 125 50, 60 40, 60 110, 125 100 " +
                    "M 150 0 L 150 100, 200 100 " +
                    "M 225 0 L 225 100, 275 100 " +
                    "M 300 50 A 25 50 0 1 0 300 49.9")
            };

            (this.Content as Grid).Children.Add(path);
        }

        Geometry PathMarkupToGeometry(string pathMarkup)
        {
            string xaml = 
                "<Path " + 
                "xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" +
                "<Path.Data>" + pathMarkup + "</Path.Data></Path>";

            Path path = XamlReader.Load(xaml) as Path;

            // Detach the PathGeometry from the Path
            Geometry geometry = path.Data;
            path.Data = null;
            return geometry;
        }

и вот мой (нефункциональный) код C++/WinRT:

    MainWindow::MainWindow()
    {
        InitializeComponent();
 
        std::string str;
        str = "M 0 0 L 0 100 M 0 50 L 50 50 M 50 0 L 50 100 ";
        str += "M 125 0 C 60 -10, 60 60, 125 50, 60 40, 60 110, 125 100 ";
        str += "M 150 0 L 150 100, 200 100 ";
        str += "M 225 0 L 225 100, 275 100 ";
        str += "M 300 50 A 25 50 0 1 0 300 49.9";
        Path path;
        path.Stroke(SolidColorBrush(Colors::Red()));
        path.StrokeThickness(12);
        path.StrokeLineJoin(PenLineJoin::Round);
        path.HorizontalAlignment(HorizontalAlignment::Center);
        path.VerticalAlignment(VerticalAlignment::Center);
        path.Data(PathMarkupToGeometry(str));

        Grid().Children().Append(path);
    }

    Geometry MainWindow::PathMarkupToGeometry(const std::string& pathMarkup)
    {
        std::string xaml = "<Path ";
        xaml += "xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>";
        xaml += "<Path.Data>";
        xaml += pathMarkup;
        xaml += "</Path.Data></Path>";

        hstring str = winrt::to_hstring(xaml);
        auto tmpl = XamlReader::Load(str);

        Path path(tmpl.try_as<Path>());
        Geometry geometry = path.Data();
        return geometry;
    }

Код в первой функции, которая устанавливает path.Data, приводит к возникновению ошибки в Microsoft.UI.Xaml.h, в функции OnLaunched в структуре product(). Причина ошибки в том, что параметр 'args' равен 0.

Мне потребовалось несколько часов, чтобы заставить это даже скомпилировать. (Спасибо IInspectable за ссылку на try_as в комментарии к другому вопросу.) Я надеюсь, что кто-то, кто знает C++/WinRT, легко увидит мою ошибку. Любая помощь будет принята с благодарностью.

Я надеялся, что приведенный выше код напечатает HELLO в главном окне. Кажется, что во второй функции все идет хорошо, пока tmpl не превратится в Path. После этого я не знаю, как определить, правильно ли передаются данные или нет.

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

Ответы 1

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

Вы забыли отсоединить геометрию от пути, и конструктор просто создает новую сетку, а не получает сетку из текущего содержимого.

Строгий эквивалент будет следующим (обратите внимание, что лучше использовать std::wstring, чтобы извлечь выгоду из естественных hstring преобразований - Windows уже давно использует Unicode):

  using namespace winrt;
  using namespace Windows::Foundation;
  using namespace Microsoft::UI;
  using namespace Microsoft::UI::Xaml;
  using namespace Microsoft::UI::Xaml::Controls;
  using namespace Microsoft::UI::Xaml::Media;
  using namespace Microsoft::UI::Xaml::Markup;
  using namespace Microsoft::UI::Xaml::Shapes;

  ...

    MainWindow::MainWindow()
    {
        InitializeComponent();

        std::wstring str;
        str = L"M 0 0 L 0 100 M 0 50 L 50 50 M 50 0 L 50 100 ";
        str += L"M 125 0 C 60 -10, 60 60, 125 50, 60 40, 60 110, 125 100 ";
        str += L"M 150 0 L 150 100, 200 100 ";
        str += L"M 225 0 L 225 100, 275 100 ";
        str += L"M 300 50 A 25 50 0 1 0 300 49.9";
        Path path;
        path.Stroke(SolidColorBrush(Colors::Red()));
        path.StrokeThickness(12);
        path.StrokeLineJoin(PenLineJoin::Round);
        path.HorizontalAlignment(HorizontalAlignment::Center);
        path.VerticalAlignment(VerticalAlignment::Center);
        path.Data(PathMarkupToGeometry(str));

        Content().try_as<Grid>().Children().Append(path);
    }

    Geometry MainWindow::PathMarkupToGeometry(const std::wstring& pathMarkup)
    {
        std::wstring xaml = L"<Path ";
        xaml += L"xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>";
        xaml += L"<Path.Data>";
        xaml += pathMarkup;
        xaml += L"</Path.Data></Path>";

        auto path = XamlReader::Load(xaml).try_as<Path>();

        Geometry geometry = path.Data();
        path.Data(nullptr);
        return geometry;
    }

Как правило, лучше использовать XAML, привязки, шаблоны, элементы управления, настраиваемые элементы управления и т. д., чем загружать и изменять необработанный XAML «вручную», но я сохранил дух исходного кода. Также книга Петцольда может немного отставать от всего нового WinUI3. И все это намного проще в C#, но это уже другая тема :-)

Большое спасибо! Этих двух крошечных изменений было достаточно, чтобы программа заработала.

dr_eck 04.11.2022 16:56

Я прекрасно понимаю, что C# значительно упростит задачу, но мне нужно выжать из моей программы все, что можно, и я не хочу использовать один язык для пользовательского интерфейса, а другой — для вычислений. Я знаю, что книга Петцольда устарела, но она должна помочь мне начать.

dr_eck 04.11.2022 17:02

@dr_eck - чего бы это ни стоило, и если вы не будете делать очень специфические вещи, мало шансов, что вы получите какой-либо прирост производительности в пользовательском интерфейсе, используя C++ вместо C#. И вы можете довольно легко смешивать C# и C++ в проекте.

Simon Mourier 04.11.2022 17:28

Вы можете довольно легко смешивать их, если знаете оба языка ;-) После краткого знакомства с C++/CLI, когда он был новым, я решил придерживаться стандартного C++. Именно поэтому я так долго использовал MFC. Я очень доволен тем, что C++/WinRT и WinUI 3 позволяют мне писать современные классические приложения на стандартном C++.

dr_eck 04.11.2022 23:38

«И все это намного проще в C#». Нет никаких технических причин, почему это так. Истинная причина в том, что Microsoft решила сохранить свой проект мусорной игрушки, который лежит в основе всего стека XAML («Компилятор XAML»), в собственность. Если бы он когда-нибудь стал открытым, мы могли бы по крайней мере попытаться исправить с его помощью самые вопиющие ошибки и решить большинство проблем, связанных с XAML, с помощью C++/WinRT. Очевидно, что некоторые из этих исправлений сломают код C# (что меня вполне устроит), поэтому, даже если проблемы будут выявлены, они не будут исправлены.

IInspectable 05.11.2022 13:22

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