首页 > 其他分享 >简单在 WinUI 仿造 WPF 的 ColumnDefinition SharedSizeGroup 共享列宽功能

简单在 WinUI 仿造 WPF 的 ColumnDefinition SharedSizeGroup 共享列宽功能

时间:2024-08-11 08:59:21浏览次数:12  
标签:SharedSizeGroup group 代码 WinUI var static currentFrameworkElement 列宽 public

本文将告诉大家如何在 WinUI 3 或 UNO 里面,仿造 WPF 的 ColumnDefinition SharedSizeGroup 共享列宽功能

本文的实现代码是大量从 https://github.com/Qiu233/WinUISharedSizeGroup 抄的,感谢大佬提供的代码。我在此基础上简化了对 Behavior 的依赖,在本文末尾放上了全部代码的下载方法

实现效果如下:

在界面放入两个 Grid 容器,这两个 Grid 容器分别都有两列,其中第零个 Grid 里面的首列放入一个带背景的 Border 控件,默认情况下宽度被压缩,期望能通过 SharedSizeGroup 的能力共享其他 Grid 的列宽而被撑开。第一个 Grid 里面的首列放入一个按钮,按钮点击的时候修改按钮的宽度,代码如下

  <Grid local:ColumnSharedSizeHelper.IsSharedSizeScope="true">
    <Grid.RowDefinitions>
      <RowDefinition Height="100"></RowDefinition>
      <RowDefinition Height="100"></RowDefinition>
    </Grid.RowDefinitions>

    <Grid x:Name="Grid1">
      <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
      </Grid.ColumnDefinitions>
      <Border Background="Blue" local:ColumnSharedSizeHelper.SharedSizeGroup="S1"></Border>
    </Grid>
    <Grid Grid.Row="1">
      <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
      </Grid.ColumnDefinitions>
      <Button Width="100" local:ColumnSharedSizeHelper.SharedSizeGroup="S1" Click="Button_OnClick"/>
    </Grid>
  </Grid>

如以上代码可以看到添加了名为 ColumnSharedSizeHelper 的辅助类用来提供 IsSharedSizeScope 和 SharedSizeGroup 附加属性,这两个附加属性和在 WPF 中有一点不一样的是不能放入在 ColumnDefinition 里面。现实中我也确实没有想到什么办法可以附加到 ColumnDefinition 里面实现功能。这也就让我仿造的功能比 WPF 弱

在后台代码里面的 Button_OnClick 只修改按钮宽度,代码如下

    private void Button_OnClick(object sender, RoutedEventArgs e)
    {
        var button = (Button) sender;
        button.Width += 100;
    }

运行代码的界面效果如下图

核心代码是 ColumnSharedSizeHelper 类型,其实现逻辑如下

public static class ColumnSharedSizeHelper
{
    // Copy From https://github.com/Qiu233/WinUISharedSizeGroup

    public static readonly DependencyProperty IsSharedSizeScopeProperty =
        DependencyProperty.RegisterAttached("IsSharedSizeScope", typeof(bool), typeof(UIElement), new PropertyMetadata(false));

    private static readonly DependencyProperty SharedSizeGroupProperty =
        DependencyProperty.RegisterAttached("SharedSizeGroup", typeof(string), typeof(UIElement), new PropertyMetadata(null));

    public static void SetIsSharedSizeScope(DependencyObject o, bool group) => o.SetValue(IsSharedSizeScopeProperty, group);
    public static bool GetIsSharedSizeScope(DependencyObject o) => (bool) o.GetValue(IsSharedSizeScopeProperty);

    public static void SetSharedSizeGroup(DependencyObject o, string group)
    {
        o.SetValue(SharedSizeGroupProperty, group);

        if (o is FrameworkElement framework)
        {
            framework.Loaded -= FrameworkOnLoaded;
            framework.Loaded += FrameworkOnLoaded;

            void FrameworkOnLoaded(object sender, RoutedEventArgs e)
            {
                TrySetSize(framework);

                framework.SizeChanged -= Framework_SizeChanged;
                framework.SizeChanged += Framework_SizeChanged;
            }
        }
    }

    private static void Framework_SizeChanged(object sender, SizeChangedEventArgs args)
    {
        if (sender is not FrameworkElement currentFrameworkElement)
        {
            return;
        }

        TrySetSize(currentFrameworkElement);
    }

    private static void TrySetSize(FrameworkElement currentFrameworkElement)
    {
        var sharedSizeGroup = GetSharedSizeGroup(currentFrameworkElement);

        if (string.IsNullOrEmpty(sharedSizeGroup))
        {
            return;
        }

        if (currentFrameworkElement.Parent is not Grid grid)
        {
            throw new InvalidOperationException();
        }

        FrameworkElement p = currentFrameworkElement;
        while (!ColumnSharedSizeHelper.GetIsSharedSizeScope(p))
        {
            if (VisualTreeHelper.GetParent(p) is not FrameworkElement fe)
            {
                return;
            }
            else
            {
                p = fe;
            }
        }

        if (p == currentFrameworkElement)
        {
            return;
        }

        if (!ColumnSharedSizeHelper.GetIsSharedSizeScope(p))
        {
            return;
        }

        var group = p.GetValue(GroupsProperty) as Dictionary<string, ColumnSharedSizeGroup>;
        if (group == null)
        {
            group = new Dictionary<string, ColumnSharedSizeGroup>();
            p.SetValue(GroupsProperty, group);
        }

        if (!group.TryGetValue(sharedSizeGroup, out var columnSharedSizeGroup))
        {
            columnSharedSizeGroup = new ColumnSharedSizeGroup();
            group.Add(sharedSizeGroup, columnSharedSizeGroup);
        }

        columnSharedSizeGroup.Update(currentFrameworkElement);
    }

    public static string GetSharedSizeGroup(DependencyObject o)
    {
        return (string) o.GetValue(SharedSizeGroupProperty);
    }

    public static readonly DependencyProperty GroupsProperty =
        DependencyProperty.RegisterAttached(nameof(ColumnSharedSizeGroup), typeof(Dictionary<string, ColumnSharedSizeGroup>), typeof(UIElement),
            new PropertyMetadata(null));

    class ColumnSharedSizeGroup
    {
        public void Update(FrameworkElement currentFrameworkElement)
        {
            var grid = (Grid) currentFrameworkElement.Parent;
            var value = (int) currentFrameworkElement.GetValue(Grid.ColumnProperty);

            var column = grid.ColumnDefinitions[value];
            if (!_columns.Contains(column))
            {
                _columns.Add(column);
            }
            var adjustments = new List<ColumnDefinition>();
            var width = currentFrameworkElement.ActualWidth + currentFrameworkElement.Margin.Left + currentFrameworkElement.Margin.Right;
            if (width > _columnSize)
            {
                _columnSize = width;
                adjustments.AddRange(_columns);
            }
            else
            {
                adjustments.Add(column);
            }

            foreach (var columnDefinition in adjustments)
            {
                columnDefinition.Width = new GridLength(_columnSize);
            }
        }

        private readonly List<ColumnDefinition> _columns = [];
        private double _columnSize = 0.0;
    }
}

本文代码放在 githubgitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 48c6e653a28a5f5609738a288b9b34b31f37c18c

以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 48c6e653a28a5f5609738a288b9b34b31f37c18c

获取代码之后,进入 UnoDemo/JeawehonawbuWhaikeregaryere 文件夹,即可获取到源代码

更多技术博客,请参阅 博客导航

标签:SharedSizeGroup,group,代码,WinUI,var,static,currentFrameworkElement,列宽,public
From: https://www.cnblogs.com/lindexi/p/18353046

相关文章

  • 1、.Net UI框架:WinUI - .Net宣传系列文章
    WinUI(WindowsUILibrary)是微软提供的一个用于构建Windows应用程序的本机UI平台组件。它与Windows应用SDK紧密相关,允许开发者创建适用于Windows10及更高版本的应用程序,并且可以发布到MicrosoftStore。WinUI3是最新的一代,它提供了与操作系统分离的整个WinUIstack,支持F......
  • 使用Aspire优雅的进行全栈开发——WinUI使用Semantic Kernel调用智普清言LLM总结Asp.N
    前言这算是一篇学习记录博客了,主要是学习语义内核(SemanticKernel)的实践,以及Aspire进行全栈开发的上手体验,我是采用Aspire同时启动API服务,Blazor前端服务以及WinUI的桌面端项目,同时进行三个项目的代码修改,整体感觉很方便,如果代码都修改了只需要启动Aspire项目,不用每个项目单独起......
  • Java使用EasyExcel自定义合并(横纵合并)、自定义行高列宽、自适应行高列宽工具Excel导出
    目录一、自适应行高列宽工具类1、自适应行高2、自适应列宽二、自定义行高列宽工具类1、自定义行高2、自定义列宽三、自定义合并工具类四、自定义样式五、实现Excel的完整代码最近又开始写Excel导出的业务,之前写的自适应行高列宽工具类并不满足现下的需求需求是导出......
  • dotnet WinUI3 Win2D 翻转图片
    本文将告诉大家如何在WinUI3里面使用Win2D进行图片的翻转,本文的方法也适用于UWP框架图片的翻转在Win2D里面,可以使用Transform2DEffect特效来辅助实现,核心逻辑就是通过缩放矩阵当成2D翻转矩阵,将缩放的X和Y传入负数即可分别实现对应方向的翻转。比如左右水平翻转可将......
  • UWP WinUI 制作一个路径矢量图标按钮样式入门
    本文将告诉大家如何在UWP或WinUI3或UNO里,如何制作一个路径按钮。路径按钮就是使用几何路径轮廓表示内容的按钮,常见于各种图标按钮,或svg系贴图矢量图按钮在网上有非常多矢量图库,其中免费的图库也非常多,比如https://www.iconfont.cn/等等。在咱的应用程序里面,可以使用这......
  • Qt QTableView设置自适应行高、列宽、行样式
    1、QTableView设置自适应行高ui->tableViewMonitor->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);//自动设置行高2、QTableView设置自适应列宽ui->tableViewMonitor->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents)......
  • 【转】[C#][WPF] GridControl 列宽控制
    在设置DevExpress里的GridControl自动列宽时,有两个方式:view.BestFitColumn(gridColumn);view.BestFitColumns();但我想要达到这样的效果:1、加载配置,读取列宽2、未配置列宽的列自动列宽发现可以这样组合://如果已配置列宽,自动列宽就是配置的宽度if(gridColumn.Widt......
  • WinAppSDK / WinUI3 项目无法使用 SystemEvents 的问题
    SystemEvents是一个开发win32窗口项目很常用的类,其中封装了一些常用的系统广播消息。在WinUI3项目中,SystemEvents事件经常无法触发,简单排查了一下原因。SystemEvent内封装了一个线程和一个窗口,通过窗口消息在内部线程上调用事件,内部使用了SystemEventInvokeInfo对象来保......
  • Antd ProTable 设置表格头,可拖动变换列宽度
    ProTable表格本身是不支持,列宽度可拖动的。1、按照一个插件( react-resizable)npm install --save react-resizable2、新建一个工具类ResizableTableUtil.jsimportReactfrom'react';import{Resizable}from'react-resizable';constResizableTitle=(props)=>......
  • Qt QTableWidget 设置列宽行高大小的几种方式及其他常用属性设置
    效果:1.列宽、行高自动分配1//列宽自动分配2tableWidget.horizontalHeader().sectionResizeMode(QHeaderView::Stretch)3//行高自动分配4tableWidget.verticalHeader().SectionResizeMode(QHeaderView::Stretch)2.固定值tableWidget.horizontalHeader().SectionResi......