Home > Enterprise >  How can I pass a property as a param to Converter and property is outside of list itemsource context
How can I pass a property as a param to Converter and property is outside of list itemsource context

Time:12-28

I am working on Listview, one of Label inside Cell using Converter, I need to pass one property as converter parameter which is not part of itemsource but defined in viewmodel.

This is my code

<Label FontSize="10"    
Text="Insufficient Funds"                                              
IsVisible="{Binding balance, Converter={StaticResource IsInsufficientBalanceConverter}, Source={x:Reference Name=multiCardPage}, ConverterParameter={x:Reference BindingContext.Subtotal} }">

Getting this exception

Xamarin.Forms.Xaml.XamlParseException: 'Position 120:52. Can not find the object referenced by BindingContext.Subtotal'

What I want to do :
I have a value Subtotal (not part of itemsource). In itemsource, there is balance property, if balance is less than Subtotal, I want to display above Insufficient Funds Label otherwise this Label should be invisible. For this I want to pass Subtotal to Converter with balance so that I can get true or false value.

How can I make it work ?

Edit 1: I want view and converter to listen the changes in subtotal value and update the UI accordingly so that Insufficient balance label can visible/invisible as per balance in listview. I have tried multibindings but that is not supporting the case with list/collection. How can I fix this.

CodePudding user response:

How can I pass a property as a param to Converter and property is outside of list itemsource context xaml - Xamarin

You don't need to pass the Subtotal as a param to Converter, you can just refer the Subtotal in your Converter class.

Please refer to the following code(suppose the type of Subtotal is int):

public class InsufficientBalanceConverter : IValueConverter
{
    const int Subtotal = 5;
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
         int mValue =  (int)value;

        if (mValue < Subtotal)
        {

            return true;
        }
        else {
            return false;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

In the xaml, we can do like this:

<Label x:Name="mQuantity" Text="Insufficient Funds"    
       IsVisible="{Binding balance, Converter={StaticResource MyInsufficientBalanceConverter} }" />

And the Resources in xaml is:

<ContentPage.Resources>
    <ResourceDictionary>
        <converts:InsufficientBalanceConverter x:Key="MyInsufficientBalanceConverter"></converts:InsufficientBalanceConverter>
    </ResourceDictionary>
</ContentPage.Resources>

Update:

Subtotal is getting updated every time user removes times from cart, in that case converter will have the old subtotal value.

You can define a static global variable for subtotal (instead of a constant) in your other class and refer it in the InsufficientBalanceConverter . In this condition, once the value of Subtotal is changed , we can get the latest the value of Subtotal.

For example:

public class Variables
{  // here we can change the value of `Subtotal `as we need.
     public static int Subtotal = 5;
}

And we can refer it like this:

public class InsufficientBalanceConverter : IValueConverter
{
     //public  static int  Subtotal = 5;
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
         int mValue =  (int)value;

        if (mValue < Variables.Subtotal)
        {

            return true;
        }
        else {
            return false;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

CodePudding user response:

You can escape the DataContext of the individual item in the ItemSource by targetting the parent ItemsControl's DataContext with RelativeSource:

<TextBlock Text="{Binding DataContext.SubTotal, 
      RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />

You could also go all of the way up to the Window or UserControl that the viewmodel backs:

<TextBlock Text="{Binding DataContext.SubTotal, 
      RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>

<TextBlock Text="{Binding DataContext.SubTotal, 
      RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />

Alternatively, you can add an x:Name="abcd" to a specific element, like a UserControl or Window (whatever is top-level for the viewmodel) and target the other DataContext by name instead:

<Window x:Name="abcd">
....

<TextBlock Text="{Binding DataContext.SubTotal, ElementName=abcd}" />
  • Related