如何使用 WPF 将十进制值作为命令参数传递给命令?

How do I pass decimal value as CommandParameter for a command using WPF?

我有一个在 Prism 6 框架之上使用 c# 和 WPF 编写的应用程序。

我正在尝试使用 XAMl 创建一个按钮,单击时,我想将一个固定的十进制值传递给我的视图模型。

<Button Content="5"
        VerticalAlignment="Center"
        HorizontalAlignment="Center"
        Command="{Binding ProcessAmount}"
        CommandParameter="5.00000"
        FontSize="24"
        Height="75"
        Width="85" />

在我的视图模型中,我有以下内容

public class ViewModel : BindableBase
{
    public DelegateCommand<decimal?> ProcessAmount { get; set; }

    public ViewModel()
    {
        ProcessAmount = new DelegateCommand<decimal?>(HandleProcessAmount, CanProcessAmount);
    }

    private bool CanProcessAmount(decimal? amount)
    {
        return amount.HasValue && amount.Value != 0;
    }

    private void HandleProcessAmount(decimal? amount)
    {
        // do something with the amount
    }
}

但是当我编译应用程序时,XAML 视图中出现错误 Specified cast is not valid.

如何从视图中发送固定的十进制值?

与其直接将 5.00000 分配给 CommandParameter,不如尝试将 XAML 中的值定义为资源(​​根据 this topic)。您的 XAML 代码可能看起来像这样

<Window x:Class="WpfApp1.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"
        mc:Ignorable="d"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow"
        Height="450"
        Width="800">

    <Window.Resources>
        <system:Double x:Key="MyDouble">5.0000</system:Double>
    </Window.Resources>

    <Grid>
        <Button Content="5"
                VerticalAlignment="Center"
                HorizontalAlignment="Center"
                Command="{Binding ProcessAmount}"
                CommandParameter="{StaticResource MyDouble}"
                FontSize="24"
                Height="75"
                Width="85" />
    </Grid>
</Window>

在Xaml世界中,每个数字都被视为Double。您需要手动转换/转换,否则可能会出现意外情况。这意味着,在您的视图模型中,将数字检索为 double? 而不是 decimal?,然后适当地将其转换/转换为 decimal。例如:

public class ViewModel : BindableBase
{
    public DelegateCommand<double?> ProcessAmount { get; set; }

    public ViewModel()
    {
        ProcessAmount = new DelegateCommand<double?>(HandleProcessAmount, CanProcessAmount);
    }

    private bool CanProcessAmount(double? amount)
    {
        return amount.HasValue && amount.Value != 0;
    }

    private void HandleProcessAmount(double? amount)
    {
        decimal amountInDecimal = Convert.ToDecimal(amount.Value); // convert it to decimal

        // do something with the amount
    }
}

这样做的好处是,double 类型的数字比 decimal 类型的数字更容易计算。但是,我想这不是你想要的。

您问题的解决方案 是在xaml 中将类型明确指定为Decimal。您需要导入 System mscorlib,然后将 SystemDecimal 分配给 CommandParameter.

xmlns:s="clr-namespace:System;assembly=mscorlib"

<Button Content="5"
        VerticalAlignment="Center"
        HorizontalAlignment="Center"
        Command="{Binding ProcessAmount}"
        FontSize="24"
        Height="75"
        Width="85">
    <Button.CommandParameter>
        <s:Decimal>5.00000</s:Decimal>
    </Button.CommandParameter>
</Button>

这消除了在 VM 端转换数字类型的必要。

您遇到的问题是,您将 string“5”分配给了 CommandParameter。有几种解决方案。其中之一是在 XAML 中设置 Decimal

<Window x:Class="....." 
xmlns:sys="clr-namespace:System;assembly=mscorlib"  
/>
<Button Content="5"
    VerticalAlignment="Center"
    HorizontalAlignment="Center"
    Command="{Binding ProcessAmount}"
    FontSize="24"
    Height="75"
    Width="85">
    <Button.CommandParameter><sys:Decimal>5.00000</sys:Decimal></Button.CommandParameter>
    <!-- <Button.CommandParameter><x:Null/></Button.CommandParameter> If you want to set value to null-->
</Button>


或将 ComandParameter 作为 string 处理:

public class ViewModel : BindableBase
{
    public DelegateCommand<string> ProcessAmount { get; set; }

    public ViewModel()
    {
        ProcessAmount = new DelegateCommand<string>(HandleProcessAmount, CanProcessAmount);
    }

    private bool CanProcessAmount(string amountStr)
    {
        try
        {
            return Convert.ToDecimal(amountStr) != 0;
        }
        catch (Exception)
        {
            return false;
        }
    }

    private void HandleProcessAmount(string amount)
    {
        // do something with the amount
    }
}