可能是.Net平台最快的UI框架gpui-dotnet

盼望着,盼望着.我们总算盼来了.Net版的GPUI封装.

大家好,我是搬砖工,最新新鲜出炉的,应该还没有超过一天的项目

gpui-dotnet

Clone项目

 git clone https://github.com/akeit0/gpui-dotnet

直接使用VS编译

先决条件:

  1. Rust工具链.
  2. Dotnet 10.0 SDk

第一次编译会编译gpui的c版本的dll.需要一点时间.直接编译Sample项目就会自动编译.不需要特殊处理.

Galley

在这里插入图片描述

长列表

功能介绍

得益于GPUI的功能完备.第一个preview版其实已经很刊用了.
几乎所有的组件

  • 菜单栏
  • 输入框
  • 虚拟化的列表/表格
  • 弹框
  • 多窗口.

作为preview功能真的很多了,我们接着来自己实现个例子.

超长列表

我们已经很熟悉GPUI了.就不再搞那种Counter不太有技术含量的东西.这次我们使用虚拟列表来处理
实体类.不用实现INPC这种WPF需要的依赖熟悉了.直接最简单最直接的User类

  public class User
  {
      public int Id { get; set; }
      public required string Name { get; set; }
      public int Age { get; set; }
      public double Score { get; set; }
  }

编写View页
View需要通过SG源代码生成器查找[GpuiView]来生成辅助代码.主要由Rust调用.
同时.我们还需要处理如何渲染一列数据的方法.同样用 [GpuiListItem]标注下.

[GpuiView]
internal sealed partial class UserTableView : View
{
  [GpuiListItem]
  private Element ServiceRow(int index, ref RenderContext ui)
  {
      var theme = ui.Theme;
      var colors = theme.Colors;
      var u = _users[0];
      if (index < _users.Count)
      {
          u = _users[index];
      }
      var selected = index == _selected;
      var status =
          index % 11 == 0 ? "degraded"
          : index % 3 == 0 ? "draining"
          : "healthy";
      var statusColor =
          status == "healthy" ? colors.Success
          : status == "draining" ? colors.Warning
          : colors.Error;
      // Cells compose inside an explicit horizontal container: divs are block by default,
      // so the row must declare its own row layout. The cell widths reconcile against this
      // container, which stretches to the full row width.
      return ui.Button(
              "service-row",
              ui.HStack(
                      ui.TableCell(
                          0,
                          ui.Text($"{u.Id}")
                              .FontSize(Px(theme.Typography.BodySmall))
                              .TextColor(colors.Text)
                      ),
                      ui.TableCell(
                          1,
                          ui.Text(u.Name)
                              .FontSize(Px(theme.Typography.Detail))
                              .TextColor(colors.TextMuted)
                      ),
                      ui.TableCell(2, ui.Text(Region(u.Age)).TextColor(statusColor)),
                      ui.TableCell(
                          3,
                          ui.Text(Throughput(index))
                              .FontSize(Px(theme.Typography.Detail))
                              .TextColor(colors.TextMuted)
                      )
                  )
                  .Width(Percent(100))
          )
          .ItemId(checked((ulong)index) + 1)
          .OnClick(this, (view, e) => view.SelectRow(e))
          .Width(Percent(100))
          .Padding(Px(selected ? 12 : 9))
          .Background(selected ? colors.ElementSelected : colors.SurfaceBackground)
          .BorderColor(selected ? colors.BorderSelected : colors.BorderVariant)
          .TextColor(selected ? colors.TextAccent : colors.Text)
          .BorderWidth(Px(1));
  }

  protected override Element Render(ref RenderContext ui)
  {
      var theme = ui.Theme;
      var header = ui.HStack(
              ui.Text($"{ItemCount:N0} services")
                  .FontSize(Px(theme.Typography.Body))
                  .TextColor(theme.Colors.Text),
              ui.Spacer(),
              ui.Badge(ui.Text(_selected < 0 ? "select a row" : $"selected: svc-{_selected:D4}"))
                  .Background(theme.Colors.InfoBackground)
                  .TextColor(theme.Colors.Info)
                  .Padding(Px(7))
          )
          .ItemsCenter();

      var grid = ui.Table(
              ref _grid,
              new ListDataSource(ItemCount, 1),
              Rows.ServiceRow,
              new TableOptions(
                  batchSize: 64,
                  overdraw: 320,
                  estimatedItemHeight: 38,
                  scrollbarGutter: true
              ),
              Columns
          )
          .Grow()
          .Width(Percent(100))
          .Background(theme.Colors.SurfaceBackground)
          .BorderColor(theme.Colors.BorderVariant)
          .BorderWidth(Px(1))
          .Radius(Px(8));

      return ui.VStack(header, grid).Gap(Px(10)).Grow();
  }

}

我们调整主界面的生成方法

 protected override Element Render(ref RenderContext ui)
 {
     var theme = ui.Theme;
     var sidebar = RenderSidebar(ref ui);
     var page = _page switch
     {
         SamplePage.Overview => ui.Child<DashboardView>("content"),
         SamplePage.Activity => ui.Child<ActivityView>("content"),
         SamplePage.Tables => ui.Child<UserTableView>("content"),
         SamplePage.Images => ui.Child<ImageGalleryView>("content"),
         SamplePage.Inputs => ui.Child<InputGalleryView>("content"),
         SamplePage.Overlays => ui.Child<OverlayGalleryView>("content"),
         SamplePage.Windows => RenderWindowGallery(ref ui),
         _ => throw new InvalidOperationException("Unknown sample page."),
     };
     var pageSlot = ui.VStack(page).Grow().Height(Percent(100));
}
``

最终的UI
![在这里插入图片描述](https://img2024.cnblogs.com/blog/322027/202609/322027-20260902154104988-1325581567.png)


## 快速刷新

现在我们已经实现了长列表的虚拟化.但是博主表示还没有尽兴.需要再实现个快速刷新功能.代码如下:

```cs
  protected override void OnMounted(ref ViewContext context)
  {
      var c = context;
      base.OnMounted(ref context);
      Task.Run(async () =>
      {
          while (true)
          {
                  await Task.Delay(20);
                  if (_selected<0)
                  {
                      _selected = 0;
                  }
                  Dispatcher.Post(() =>
                  {
                      _grid.Refresh(_selected, 10);
                  });
          }

      });
  }

我们设置了20ms一次的更新.看看效果:

在这里插入图片描述

最后.我们看下内存的占用:

在这里插入图片描述

不仅UI框架块.搬砖工的速度也快.

感谢大家观看.今天我们就分享到这里.欢迎关注.多多转发.最新文章下方留言

我是搬砖工,欢迎大家多多关注,多多点赞.多多下方交流

logo

posted on 2026-09-02 15:42  HelyCheng  阅读(30)  评论(0)    收藏  举报

导航