Issue
I am trying to find a way to handle the fact that CommandParameter is not bindable with IValueConverter. Through reading I found a suggestion to Inherit from BindableObject while implementing IValueConverter.
When attempting to access the property, it is always 0, presumably taking the default value.
For reference, I am simplifying the problem by using the Xamarin.Forms Shell Template as an example:
When making the project use Mobile App (Xamarin.Forms) and select Shell when creating the project. From there I made a small amount of modifications. Please note that I am merely setting a breakpoint to view what is assigned to the BindableProperty, which is always 0.
This example adds two properties to the already provided Item.cs class.
public class Item {
public string Id { get; set; }
public string Text { get; set; }
public string Description { get; set; }
// Added these two properties. The idea is to Bind Number1 to the Text property of a label, and pass Number2 to the Property
public int Number1 { get; set; }
public int Number2 { get; set; }
}
In the constructor of MockDataStore.cs I added values for both Number1 and Number2 properties.
var mockItems = new List<Item>{
new Item { Id = Guid.NewGuid().ToString(), Text = "First item", Description="This is an item description.", Number1 = 5, Number2 = 20},
new Item { Id = Guid.NewGuid().ToString(), Text = "Second item", Description="This is an item description.", Number1 = 2, Number2 = 8},
new Item { Id = Guid.NewGuid().ToString(), Text = "Third item", Description="This is an item description.", Number1 = 3, Number2 = 6},
new Item { Id = Guid.NewGuid().ToString(), Text = "Fourth item", Description="This is an item description.", Number1 = 4, Number2 = 7},
new Item { Id = Guid.NewGuid().ToString(), Text = "Fifth item", Description="This is an item description.", Number1 = 1, Number2 = 10},
new Item { Id = Guid.NewGuid().ToString(), Text = "Sixth item", Description="This is an item description.", Number1 = 8, Number2 = 2}
};
The Converter with BindableObject and IValueConverter
public class Number1Number2Converter : BindableObject, IValueConverter {
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(nameof(Value), typeof(int), typeof(Number1Number2Converter), null);
public int Value {
get {
return (int)GetValue(ValueProperty);
}
set {
SetValue(ValueProperty, value);
}
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
// object value does have a value assigned, which is good however the bound Property of Value does not. This should have Number2 being passed in.
var testing123 = Value;
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return null;
}
}
On the line with var testing123 = Value; I placed a Breakpoint. I am not yet attempting to use Value, I just want to see it not being 0. Not one of the values I assigned Number2 in the MockDataStore is 0.
Here is the modified ItemsPage.xaml. Note the Label with Number1 bound and of course the Converter.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="clr-namespace:App2.Converters;assembly=App2"
mc:Ignorable="d"
x:Class="App2.Views.ItemsPage"
Title="{Binding Title}"
x:Name="BrowseItemsPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
</ContentPage.ToolbarItems>
<StackLayout>
<ListView x:Name="ItemsListView"
ItemsSource="{Binding Items}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement"
ItemSelected="OnItemSelected">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>First Item</x:String>
<x:String>Second Item</x:String>
<x:String>Third Item</x:String>
<x:String>Forth Item</x:String>
<x:String>Fifth Item</x:String>
<x:String>Sixth Item</x:String>
</x:Array>
</d:ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding Text}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding Description}"
d:Text="Item description"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
<Label>
<Label.Text>
<Binding Path="Number1">
<Binding.Converter>
<converters:Number1Number2Converter Value="{Binding Path=Number2}" />
</Binding.Converter>
</Binding>
</Label.Text>
</Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
Value is always 0 in this example. The parameter object value is assigned the int value of Number1, but the bindable property of Value should be assigned Number2. Is this concept fundamentally flawed or am I on the right track but failed at implementing something?
Solution
You could try to send the whole Item object to your converter:
<Label Text="{Binding Path=., Converter={StaticResource Number1Number2Converter}}" />
Then, in your converter you should have access to both properties:
public class Number1Number2Converter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
if (value is Item item)
{
var number1 = item.Number1;
var number2 = item.Number2,
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return null;
}
}
Answered By - Isma

0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.