C# WPF:单击数据网格中嵌入的按钮时,我想触发SelectionChanged,然后单击,但不能同时单击

C# WPF:单击数据网格中嵌入的按钮时,我想触发SelectionChanged,然后单击,但不能同时单击,c#,wpf,xaml,datagrid,race-condition,C#,Wpf,Xaml,Datagrid,Race Condition,我有一个DataGrid和一份员工名单。当用户更改所选行时,我希望代码隐藏执行一个昂贵的“加载”操作,从数据库中提取数据,并阻止用户在控件上的进一步输入,直到完成为止。这目前效果很好。每行还有一个按钮,按下时,我想要: 对于要选择的按下按钮的行 对于要加载的数据 函数“打印”启动,但直到数据加载函数返回 这是我的XAML: <Window x:Class="ListViewPrintProblem.MainWindow" xmlns="http://schemas.micr

我有一个DataGrid和一份员工名单。当用户更改所选行时,我希望代码隐藏执行一个昂贵的“加载”操作,从数据库中提取数据,并阻止用户在控件上的进一步输入,直到完成为止。这目前效果很好。每行还有一个按钮,按下时,我想要:

  • 对于要选择的按下按钮的行
  • 对于要加载的数据
  • 函数“打印”启动,但直到数据加载函数返回
  • 这是我的XAML:

    <Window x:Class="ListViewPrintProblem.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            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:i="http://schemas.microsoft.com/expression/2010/interactivity"
            xmlns:listViewPrintProblem="clr-namespace:ListViewPrintProblem"
            d:DataContext="{d:DesignInstance listViewPrintProblem:MainViewModel, IsDesignTimeCreatable=True}"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525"
            DataContextChanged="MainWindow_OnDataContextChanged_OnDataContextChanged">
        <Grid>
            <DataGrid
                x:Name="StaffList"
                ItemsSource="{Binding StaffItems}"
                GridLinesVisibility="Horizontal"
                IsSynchronizedWithCurrentItem="True"
                AutoGenerateColumns="False"
                CanUserAddRows="False"
                SelectedItem="{Binding SelectedStaffItem}">
                <DataGrid.Columns>
    
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
    
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Button Name="printButton">
                                    <i:Interaction.Triggers>
                                        <i:EventTrigger EventName="Click">
                                            <i:InvokeCommandAction 
                                                Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=DataContext.PrintCommand}"  
                                                CommandParameter="{Binding ElementName=printButton, Path=Content}"/>
                                        </i:EventTrigger>
                                    </i:Interaction.Triggers>
                                </Button>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
    
                </DataGrid.Columns>
    
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction 
                            Command="{Binding SelectedStaffChangedCommand}"
                            CommandParameter="{Binding Path=SelectedItem, ElementName=StaffList}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
    
            </DataGrid>
        </Grid>
    </Window>
    

    当用户单击一行时,加载将异步运行,并且不会阻止用户输入,这很好。但是,当用户单击打印图标时,加载将异步运行,并且不会阻止打印,这是不好的。因此,打印显示的是以前选择的员工的姓名,而不是当前员工的姓名。如果我从加载中删除Task.Delay,它每次都能正常工作。

    那么你的问题是什么?我如何实现解决方案1或2?最好是#1.发布您当前在单击按钮时调用的命令的实现。好的,发布了,并提供了更多关于出错原因的详细信息。
    public string LoadedStaff { get; set; }
    private void SelectedStaffChanged(Staff newStaff)
    {
        if (LoadedStaff == newStaff?.Name) return;
    
        Task.Factory.StartNew(Load).GetAwaiter().GetResult();
    
    }
    
    private async void Load()
    {
        Loading = true;
    
        LoadedStaff = await GetNameAsync(SelectedStaffItem);
    
        Loading = false;
    }
    
    private static async Task<string> GetNameAsync(Staff selectedStaffItem)
    {
        await Task.Delay(1000);
    
        switch (selectedStaffItem?.Name)
        {
            case "Moe":
                return "Moe Howard";
            case "Larry":
                return "Larry Fine";
            case "Curly":
                return "Curly Howard";
            default:
                return "Unknown";
        }
    
    }
    
    private void MainWindow_OnPrint()
    {
        var vm = DataContext as MainViewModel;
        MessageBox.Show(vm?.LoadedStaff);
    }