You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++/WinRT+WinUI3编程设置Path几何图形?代码报错求助

C++/WinRT + WinUI3 路径标记语法转换问题

我有几十年MFC开发经验,正在学习C++/WinRT和WinUI 3,目前正在将Petzold《Programming Windows》第6版中的C#代码转换为C++/WinRT,处理第2章的PathMarkupSyntaxCode示例。尝试实现后程序报错,希望排查问题。

参考的C#代码

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函数的produce()结构体中抛出错误,原因是参数'args'为0。目标是在主窗口显示由路径标记组成的HELLO图形。

问题排查与修正

1. 错误:添加Path到临时Grid实例

原代码中Grid().Children().Append(path)创建了一个全新的临时Grid对象,并未关联到窗口的实际Content容器,导致Path无法被渲染到界面。修正为获取窗口的Content并转换为Grid:

if (auto grid = Content().try_as<Grid>())
{
    grid.Children().Append(path);
}

2. 错误:字符串编码与XAML格式问题

使用std::string转hstring可能存在编码偏差,直接改用winrt::hstring构造路径标记与XAML字符串,避免转换错误;同时XAML字符串中直接使用<和>而非转义字符(C++宽字符串无需HTML转义)。

3. 错误:Geometry所有权未解除

原C#代码中通过path.Data = null解除Geometry与原Path的关联,C++/WinRT中需要执行相同操作,否则返回的Geometry仍被原Path持有,导致新Path无法正确获取所有权:

Geometry geometry = path.Data();
path.Data(nullptr); // 解除关联
return geometry;

4. 补充:添加空指针检查

在将XamlReader加载的对象转换为Path时,添加空指针检查,避免后续操作访问无效对象。

修正后的完整代码

MainWindow构造函数

MainWindow::MainWindow()
{
    InitializeComponent();

    winrt::hstring pathMarkup = L"M 0 0 L 0 100 M 0 50 L 50 50 M 50 0 L 50 100 "
                                L"M 125 0 C 60 -10, 60 60, 125 50, 60 40, 60 110, 125 100 "
                                L"M 150 0 L 150 100, 200 100 "
                                L"M 225 0 L 225 100, 275 100 "
                                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(pathMarkup));

    // 获取窗口的Content Grid并添加Path
    if (auto grid = Content().try_as<Grid>())
    {
        grid.Children().Append(path);
    }
}

PathMarkupToGeometry函数

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

    auto xamlObj = XamlReader::Load(xaml);
    Path path = xamlObj.try_as<Path>();
    if (!path)
    {
        throw winrt::hresult_error(E_INVALIDARG, L"Failed to load Path from XAML");
    }

    Geometry geometry = path.Data();
    path.Data(nullptr); // 解除Geometry与原Path的关联
    return geometry;
}

内容的提问来源于stack exchange,提问作者dr_eck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 13:45:43