Home > other >  Can I unbox an integer with a cast in XAML?
Can I unbox an integer with a cast in XAML?

Time:02-28

I've hit a case in which I have a class that returns type object that I happen to know is merely a boxed int value. The control I am using can bind to an int property or a double property but it cannot bind to an object that is a boxed int or double. I have to work around this limitation. I'd like to do so in a very simple manner.

Edited to add: The exception that occurs when I try to do this is System.NotSupportedException with the message DoubleConverter cannot convert from System.Int32

So is there a way to make a cast to int or double in XAML that is the equivalent of an unboxing operation? I already know how to cast a reference type in XAML so I can access some specific, derived-class property. But I am having trouble with this one because int is not a type with properties.

Below is the class (a simplified version). It represents a ranged set of integers or doubles or even other types for which "min" and "max" values would be meaningful. So it has to return them all as object. Regardless, all 3 properties will return the same underlying type in the boxed value, be it double or int or something else.

public class Parameter
{
    virtual object Lower      { get; }     
    virtual object Upper      { get; }   
    virtual object Value      { get; set; } 
}

I bind to the control like this

<tk:RadNumericUpDown MinWidth="100"
    IsInteger="True"
    Value="{Binding Value, Mode=TwoWay}"
    Minimum="{Binding Lower, Mode=OneWay}"
    Maximum="{Binding Upper, Mode=OneWay}"
    />

Now if I know that the Lower property is an int, can I bind it with some sort of XAML cast? I've tried a few things

Minimum="{Binding Lower(sys:Int32), Mode=OneWay}"
Minimum="{Binding Lower.(sys:Int32), Mode=OneWay}"

I didn't expect any of these to work and they didn't. But the syntax (if there is one) eludes me. About the only way I can get this to work is to define a separate property in the class that returns the Lower as an int value

Is there a way to do an unboxing cast in XAML?

CodePudding user response:

You could run it through an IValueConverter:

public class NonConverter : IValueConverter
{
    public object Convert(object v, Type t, object p, CultureInfo c) => v;

    public object ConvertBack(object v, Type t, object p, CultureInfo c) => v;
}

Resource:

<Window.Resources>
    <local:NonConverter x:Key="nonConverter"></local:NonConverter>
</Window.Resources>

Binding:

Minimum="{Binding Lower, Mode=OneWay, Converter={StaticResource nonConverter}}"

I'm not sure if there is a simpler way.


Here is a minimal implementation using a ProgressBar, .NET Framework 4.7.2. I'm not sure what happens with two-way binding.

MainWindow.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:local="clr-namespace:WpfApp1"
        Title="MainWindow" Height="200" Width="400">
    <Window.Resources>
        <local:NonConverter x:Key="nonConverter"></local:NonConverter>
    </Window.Resources>
    <Grid>
        <ProgressBar Height="20" Width="200"
            Minimum="{Binding Lower}"
            Maximum="{Binding Upper, Converter={StaticResource nonConverter}}"
            Value="{Binding Value, Converter={StaticResource nonConverter}}"
        />
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public object Lower { get; set; }
        public object Upper { get; set; }
        public object Value { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            DataContext = this;
            
            Lower = 1000.0d; // double
            Upper = "2000"; // string 
            Value = 1500.0m; // decimal
        }
    }

    public class NonConverter : IValueConverter
    {
        public object Convert(object v, Type t, object p, CultureInfo c) => v;

        public object ConvertBack(object v, Type t, object p, CultureInfo c) => v;
    }
}

Each of the three properties are assigned a different type for illustration purposes.

The NonConverter isn't converting, casting, or un/boxing anything, it's simply returning the same input v that it received. The actual conversion is being handled by the framework.

Because Lower is a (boxed) double, the converter isn't required here.

  • Related