ValueConverter with Bindable Property

I have a Xamarin project, and I am trying to get a binding on my ValueConverter. I accomplish this in my UWP project, but in Xamarin I am getting a compilation error:

No property, bindable property, or event found for 'UserData', or mismatching type between value and property.

The purpose of this is that when you select an item in the ListView, the entry reads the UserValue property, when you edit the text in this entry, the content of the item's property is updated, and this change is visible in the ListView.

There is my code:

MainPage.XAML:

    <ListView x:Name="_ListView" ItemSelected="_ListView_ItemSelected">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Grid>
                        <Grid.Resources>
                            <local:ViewCell_Converter x:Key="ViewCell_Converter" UserData="{Binding}"/>
                        </Grid.Resources>

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="2*"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>

                        <Label Grid.Column="0" Text="{Binding UserName}"/>
                        <Label Grid.Column="1" Text="{Binding UserValue, Converter={StaticResource ViewCell_Converter}}"/>
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

MainPage.XAML.cs:

public MainPage()
{
    InitializeComponent();

    _ListView.ItemsSource = UserDatas();
}        

private ObservableCollection<UserData> UserDatas()
{
    return new ObservableCollection<UserData>()
    {
        new UserData() { UserName = "Name1", UserValue = 10, ValidatedByUser = true, },
        new UserData() { UserName = "Name2", UserValue = 11, ValidatedByUser = false, },
        new UserData() { UserName = "Name3", UserValue = 12, ValidatedByUser = true, },
        new UserData() { UserName = "Name4", UserValue = 13, ValidatedByUser = false, },
        new UserData() { UserName = "Name5", UserValue = 14, ValidatedByUser = true, },
    };
}

private void _ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
    if (e.SelectedItem is UserData userData)
    {
        Entry_NewValue.Text = userData.UserValue.ToString();
    }
}

private void Entry_NewValue_TextChanged(object sender, TextChangedEventArgs e)
{
    if (_ListView.SelectedItem is UserData userData)
    {
        if (double.TryParse(Entry_NewValue.Text, out double _double))
        {
            if(userData.UserValue != _double)
            {
                userData.UserValue = _double;
            }                
        }
    }
}

Methods.cs:

public class UserData : Prism.Mvvm.BindableBase
{
    private bool _validatedByUser;
    public bool ValidatedByUser
    {
        get
        {
            return _validatedByUser;
        }
        set
        {
            SetProperty(ref _validatedByUser, value);
        }
    }

    private string _userName;
    public string UserName
    {
        get
        {
            return _userName;
        }
        set
        {
            SetProperty(ref _userName, value);
        }
    }

    private double _userValue;
    public double UserValue
    {
        get
        {
            return _userValue;
        }
        set
        {
            SetProperty(ref _userValue, value);
        }
    }
    }

    public class ViewCell_Converter : BindableObject, IValueConverter
    {            
    public UserData UserData
    {
        get { return (UserData)GetValue(bindableProperty); }
        set { SetValue(bindableProperty, value); }
    }

    public static readonly BindableProperty bindableProperty = BindableProperty.Create(
                                                               nameof(UserData),
                                                               typeof(UserData),
                                                               typeof(ViewCell_Converter),
                                                               null);

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (UserData != null)
        {
            if (value is double _value)
            {
                if (UserData.ValidatedByUser)
                {
                    return string.Format("{0:0.00}", _value);
                }
                else
                {
                    return string.Format("{0:0.0000}", _value);
                }
            }
        }

        return null;
    }

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

Answers

  • JGoldbergerJGoldberger USMember, Forum Administrator, Xamarin Team, University Xamurai
    edited August 2018

    @jm_developer

    Can you reproduce this issue when not using Prism? Just to make sure this is an issue in Xamarin.Forms and not in Prism? Also you do not specify if your UWP app (where this works) is part of the Xamarin Forms solution and uses this same binding and value converter code or if that is a separate UWP project altogether.

    Also, you should not need a value converter to show a double value in a label, the the conversion from double to string should just work in a Label. Just tested with the following:

    <Label Text="{Binding Data}" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
    
    double _data;
        public double Data { 
            get
            {
                return _data;
            } 
            set 
            {
                if (value != _data) 
                {
                    _data = value;
                    OnPropertyChanged("Data");
                }
            } 
        }
    

    And the double value was shown in the label.

Sign In or Register to comment.