После десятилетий написания приложений 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. После этого я не знаю, как определить, правильно ли передаются данные или нет.





Вы забыли отсоединить геометрию от пути, и конструктор просто создает новую сетку, а не получает сетку из текущего содержимого.
Строгий эквивалент будет следующим (обратите внимание, что лучше использовать 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#, но это уже другая тема :-)
Я прекрасно понимаю, что C# значительно упростит задачу, но мне нужно выжать из моей программы все, что можно, и я не хочу использовать один язык для пользовательского интерфейса, а другой — для вычислений. Я знаю, что книга Петцольда устарела, но она должна помочь мне начать.
@dr_eck - чего бы это ни стоило, и если вы не будете делать очень специфические вещи, мало шансов, что вы получите какой-либо прирост производительности в пользовательском интерфейсе, используя C++ вместо C#. И вы можете довольно легко смешивать C# и C++ в проекте.
Вы можете довольно легко смешивать их, если знаете оба языка ;-) После краткого знакомства с C++/CLI, когда он был новым, я решил придерживаться стандартного C++. Именно поэтому я так долго использовал MFC. Я очень доволен тем, что C++/WinRT и WinUI 3 позволяют мне писать современные классические приложения на стандартном C++.
«И все это намного проще в C#». Нет никаких технических причин, почему это так. Истинная причина в том, что Microsoft решила сохранить свой проект мусорной игрушки, который лежит в основе всего стека XAML («Компилятор XAML»), в собственность. Если бы он когда-нибудь стал открытым, мы могли бы по крайней мере попытаться исправить с его помощью самые вопиющие ошибки и решить большинство проблем, связанных с XAML, с помощью C++/WinRT. Очевидно, что некоторые из этих исправлений сломают код C# (что меня вполне устроит), поэтому, даже если проблемы будут выявлены, они не будут исправлены.
Большое спасибо! Этих двух крошечных изменений было достаточно, чтобы программа заработала.