Avalonia 使用 TreeDataGrid 自定义模板的ContextMenu 点击并行任务。

记录这蛋疼的TreeDataGrid ,
这篇文章讲了如何使用TreeDataGrid ,但问题来了,我选中的那一行咋搞。那就以这篇文章为例子。

简单就是 JobListSource.RowSelection!.SelectionChanged += TreeSelectionChanging;

方法 TreeSelectionChanging

[ObservableProperty]
private JobList? _selectedJob;
private void TreeSelectionChanging(object? sender, TreeSelectionModelSelectionChangedEventArgs<JobList> e)
{
    var source = JobListSource.Selection  as ITreeDataGridRowSelectionModel<JobList>;
    ContextMenuType = source!.SelectedItem!.Type;
    SelectedJob = source.SelectedItem!;
}

SelectedJob就是选中的玩意。。
这样还要新建属性,然后在构造函数里写。

所以直接将创建 HierarchicalTreeDataGridSource放到一个方法里。

private  HierarchicalTreeDataGridSource<JobList> CreatJobList( ObservableCollection<JobList> navJobs)
{
    var res =  new HierarchicalTreeDataGridSource<JobList>(navJobs)
    {
        Columns =
        {
          ...
        },
    };
    res.RowSelection!.SelectionChanged += TreeSelectionChanging;
    return res;
}

构造函数赋值。

public XXViewModel()
{
     JobListSource =  CreatJobList(JobLists);
 }

好了,讲任务,一般来说 这种表格会有右键功能,但如果在ViewModel简单的写一个RelayCommand,右键点击后,在这个功能完成前,其他row的相同功能是不行继续点击的。
如果没有特殊需求就算了,但有特殊需求就要想办法了。一种是新建一个AsyncCommand

public class AsyncCommand<T>(Func<T, Task> execute, Func<T, bool>? canExecute = null) : ICommand
{
    private readonly Func<T, bool> _canExecute = canExecute ?? (_ => true);

    public bool CanExecute(object? parameter) => _canExecute(((T)parameter!));

    public async void Execute(object? parameter)
    {
        await ExecuteAsync((T)parameter!);
    }

    private async Task ExecuteAsync(T? parameter)
    {
        try
        {
            await execute(parameter!);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"命令执行失败: {ex.Message}");
        }
    }

    public event EventHandler? CanExecuteChanged;

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

然后定义这个类型的命令去写绑定就行了,但代码不够简洁且不符合 MVVM 最佳实践。
在这里插入图片描述
这是deepseek 说的。这狗日的一直让我AsyncCommand。。

伟大的MVVM党岂会容忍这狗日的。改。

既然是TreeDataGrid的row,那就很好办了。我给每一个joblist 都加一个RelayCommand不就得了?

public class JobList
{
    public string? Title { get; set; }

    public string? SiteMemo { get; set; }

    public bool? IsSelect { get; set; }
    
    public ListType Type { get; set; } = ListType.IsFile;

    public ObservableCollection<JobList> Members { get; set; } = [];

 	[RelayCommand]
    private async Task RunXX()
    {
        await xxx(Title);
    }
}

PS: 并行的用异步,微软这狗比必叫好。
想用什么值直接拿,多省心。

TreeSelectionChanging修改一下。

[ObservableProperty] private IAsyncRelayCommand XXCommand = null!;

private void TreeSelectionChanging(object? sender, TreeSelectionModelSelectionChangedEventArgs<JobList> e)
{
    var source = JobListSource.Selection  as ITreeDataGridRowSelectionModel<JobList>;
    ContextMenuType = source!.SelectedItem!.Type;
    SelectedJob = source.SelectedItem!;
    XXCommand = source.SelectedItem!.RunXXCommand;
}

然后是axaml。

<TreeDataGrid Source="{Binding JobListSource}">
    <TreeDataGrid.Resources>
        <!-- 树  -->
        <DataTemplate x:Key="JobList" x:DataType="models:JobList" >
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                <PathIcon Width="12" Height="12" Margin="8,0,12,0" Data="{Binding Type,Converter={helper:TypeToGeometryConverter}}"/>
                <TextBlock Text="{Binding Title}" VerticalAlignment="Center"/>
            </StackPanel>
        </DataTemplate>  
    </TreeDataGrid.Resources>
    <TreeDataGrid.ContextMenu>
        <ContextMenu>
            <MenuItem 
                Command="{Binding XXCommand}"
                IsVisible="{Binding ContextMenuType,Converter={helper:FileBoolConverter}}" Header="开始"/>
        </ContextMenu>
    </TreeDataGrid.ContextMenu>
</TreeDataGrid>

多优雅,多简洁,deepseek 用了都说好。这坑爹的TreeDataGrid。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值