Prism DelegateCommand 的 CanExecute 在 RaiseCanExecuteChanged 后获取空参数

Prism DelegateCommand's CanExecute getting null parameter after RaiseCanExecuteChanged

我正在尝试编写一个 ListView,其中每个项目都有一个绑定到 DelegateCommand 的按钮。我希望此命令的 CanExecute 基于项目的布尔值 属性。 ItemSource 是一个 ObservableCollection,我使用 async 方法填充它。问题是,当 RaiseCanExecuteChanged() 被触发时,CanExecute 接收 null 作为 parameter.After,当我使用另一个 UI 绑定命令到 RaiseCanExecuteChanged() 时,该方法运行正常。

这是视图的一部分:

<ListView x:Name="root" ItemsSource="{Binding olVersions}" IsSynchronizedWithCurrentItem="true" HorizontalContentAlignment="Stretch">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>

                <TextBlock Text="{Binding Path=sFullName}" Grid.Column="0" VerticalAlignment="Center"></TextBlock>
                <Button Grid.Column="1" Content="Run" CommandParameter="{Binding}" Command="{Binding ElementName=root, Path=DataContext.cRunVersionCommand}"></Button>
                <Button Grid.Column="2" Content="Download" CommandParameter="{Binding}" Command="{Binding ElementName=root, Path=DataContext.cDownloadVersionCommand}"></Button>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

这是视图模型:

public class VersionsTabViewModel : BindableBase
{

    public ObservableCollection<CVersion> olVersions { get; private set; }

    public DelegateCommand<CVersion> cRunVersionCommand { get; private set; }
    public DelegateCommand<CVersion> cDownloadVersionCommand { get; private set; }

    private IVersionManager c_version_manager;

    public VersionsTabViewModel(IVersionManager cVersionManager)
    {
        olVersions = new ObservableCollection<CVersion>();
        cRunVersionCommand = new DelegateCommand<CVersion>(v_try_run_version, b_can_run);
        cDownloadVersionCommand = new DelegateCommand<CVersion>(v_try_download_version);
        c_version_manager = cVersionManager;
        v_read_available_versions();
    }

    private async void v_read_available_versions()
    {
        List<CVersion> l_versions = await c_version_manager.lGetVersions();
        List<CVersion> l_versions_sorted = l_versions.OrderByDescending(cVersion => cVersion.cSemanticVersion).ToList();
        olVersions.Clear();
        olVersions.AddRange(l_versions_sorted);

        cRunVersionCommand.RaiseCanExecuteChanged();
    }

    private void v_try_run_version(CVersion cVersionToRun)
    {
        MessageBox.Show($"Run {cVersionToRun.sFullName}", "Run"); //TODO
    }

    private void v_try_download_version(CVersion cVersionToDownload)
    {
        MessageBox.Show($"Download {cVersionToDownload.sFullName}", "Download"); //TODO
        cRunVersionCommand.RaiseCanExecuteChanged();
    }

    private bool b_can_run(CVersion cVersion)
    {
        return cVersion?.bIsInstalled ?? false;
    }
}

这似乎是命令绑定的一般问题,有一个相关的问题,here。为了使其适用于您的情况,您必须将 ElementName 绑定从

更改为 root Command 属性
Command="{Binding ElementName=root, Path=DataContext.cRunVersionCommand}"

像这样绑定到父 ListView 控件的相对源。

Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Path=DataContext.cRunVersionCommand}"