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