Avalonia TreeDataGrid 实现复制当前格的文本

Avalonia TreeDataGrid 实现复制当前格的文本

Avalonia 的 TreeDataGrid 在 Avalonia 的文档中其实没有特别详细,你可能有一些功能想要做,为此特别贴出来。

目标:实现复制当前格的文本
你需要有 https://docs.avaloniaui.net/zh-Hans/docs/reference/controls/treedatagrid/ 的简单使用经验!

一、效果演示

界面是这个样子。

下面是剪贴板的信息。

二、xaml 界面

<Window
    x:Class="AvaloniaPlayground2.Views.MainWindow"
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:views="using:AvaloniaPlayground2.Views"
    xmlns:vm="using:AvaloniaPlayground2.ViewModels"
    Title="AvaloniaPlayground2"
    d:DesignHeight="450"
    d:DesignWidth="800"
    x:DataType="vm:MainWindowViewModel"
    mc:Ignorable="d">

    <Panel>
        <TreeDataGrid Name="PART_DataGrid" ContextRequested="TreeDataGrid_ContextRequested">
            <TreeDataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem
                        Name="PART_CopyCurrentItem"
                        Click="PART_CopyCurrentItem_Click"
                        Header="复制当前项" />
                </ContextMenu>
            </TreeDataGrid.ContextMenu>
        </TreeDataGrid>
        <Button
            HorizontalAlignment="Right"
            VerticalAlignment="Bottom"
            Click="Button_Click"
            Content="加载数据" />
    </Panel>
</Window>

三、C# 代码

using Avalonia.Controls;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Interactivity;
using System.Collections.Generic;
namespace AvaloniaPlayground2.Views
{
    public class TestItemViewModel
    {
        public string Name { get; set; }
        public string Desciption { get; set; }

        public TestItemViewModel(string name, string description)
        {
            Name = name;
            Desciption = description;
        }
    }

    public partial class MainWindow : Window
    {
        private FlatTreeDataGridSource<TestItemViewModel> _source;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object? sender, RoutedEventArgs e)
        {
            var list = new List<TestItemViewModel>()
            {
                new TestItemViewModel("测试1", "描述描述描述1"),
                new TestItemViewModel("测试2", "描述描述描述2"),
                new TestItemViewModel("测试3", "描述描述描述3"),
                new TestItemViewModel("测试4", "描述描述描述4"),
            };
            _source = new FlatTreeDataGridSource<TestItemViewModel>(list)
            {
                Columns =
                {
                    new  TextColumn<TestItemViewModel, string>("Name", i=>i.Name),
                    new TextColumn<TestItemViewModel, string>("Header", i=>i.Desciption)
                }
            };

            PART_DataGrid.Source = _source;
        }

        private void TreeDataGrid_ContextRequested(object? sender, ContextRequestedEventArgs e)
        {
            var textBlock = e.Source as TextBlock;
            if (textBlock is null) return;

            PART_CopyCurrentItem.Tag = textBlock.Text;
        }

        private async void PART_CopyCurrentItem_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
        {
            var button = sender as MenuItem;
            var tag = PART_CopyCurrentItem.Tag as string;
            if (string.IsNullOrEmpty(tag))
            {
                await Clipboard.ClearAsync();
            }
            else
            {
                await Clipboard.SetTextAsync(tag);
            }

        }
    }
}

四、省流总结

  1. ContextRequested 可以在右键菜单创建前触发,我的思路是在右键菜单打开前,读取当前格子的信息并且塞到复制按钮的Tag中,其实你也完全可以放到别的地方。
  2. TreeDataGrid_ContextRequested 的 e.Source 会直接来自当前控件,多亏了路由事件的机制,我们可以得到当前右键聚焦的控件是谁,e.Source 一般而言会是当前的 TextBlock ,如果没有文本块,按照我的经验会拿到 Border。
  3. Clipboard 可以在 Window 中拿到,如果你当前的不在 Window 这个地方,你如果在 ViewModel,或者子 View 上,那你可能需要一些依赖注入或者全局 static 实例的技巧!
posted @ 2025-06-16 10:53  fanbal  阅读(135)  评论(0)    收藏  举报