首页 > 解决方案 > Prism DelegateCommand 的 CanExecute 在 RaiseCanExecuteChanged 后获取空参数

问题描述

我正在尝试编写一个ListView,其中每个项目都有一个绑定到 a 的按钮DelegateCommand。我希望这个命令CanExecute基于项目的布尔属性。ItemSource是一个ObservableCollection,我正在使用一种async方法填充它。问题是当RaiseCanExecuteChanged()被触发时,作为参数CanExecute接收null。之后,当我使用另一个 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;
    }
}

标签: c#.netwpf.net-coreprism

解决方案


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

Command="{Binding ElementName=root, Path=DataContext.cRunVersionCommand}"

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

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

推荐阅读