3

I have an app written using c# and WPF on the top of Prism 6 framework.

I am trying to create a button using XAMl, when clicked, I want to be pass a fixed decimal value to my view-model.

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

In my view-model I have the following

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
    }
}

But when I compile the app, I get an error in the XAML view Specified cast is not valid.

How can I send a fixed decimal value from the view?

Junior
  • 11,602
  • 27
  • 106
  • 212

3 Answers3

4

In Xaml world, every number is treated as Double. You would need to cast/ convert manually, otherwise unexpected may occurs. This means, in your view model, retrieve the number as double? instead of decimal?, then cast/ convert it to decimal as appropriately. For ex:

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
    }
}

The good thing about this is that it is easier to perform calculation on double type number than decimal type number. But, I guess this is not what you wanted.

The solution to your question is specify the type explicitly to be Decimal in the xaml. You need to import the System mscorlib and then assign that System's Decimal to the 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>

This eliminates the necessary to convert number type on the VM side.

kurakura88
  • 2,185
  • 2
  • 12
  • 18
2

Instead of literally assigning 5.00000 to CommandParameter, try defining the value in XAML, as a resource (as per this topic). Your XAML code could look something like this

<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>
Mikolaj Kieres
  • 4,137
  • 1
  • 20
  • 23
0

The problem you have is, that you assign string "5" to the CommandParameter. There are several solutions. One of them to set Decimal in XAML:

<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>


or handle ComandParameter as a 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
    }
}
Rekshino
  • 6,954
  • 2
  • 19
  • 44