0

Very simplified version of my code:

ViewModels:

public class ViewModel
{
    public ObjectViewModel {get; set;}
}

public class ObjectViewModel
{
    public string MyString {get; set;}
    public bool MyStringIsValid {get; set;}
}

Xaml:

<Entry Text="{Binding ObjectViewModel.MyString}" TextChanged="Entry_TextChanged"/>
<Label Text="Valid!" IsVisible="{Binding ObjectViewModel.MyStringIsValid}"/>

In my code behind, I would like to be able to grab the bound property of Entry.Text by doing something like this:

void Entry_TextChanged(object sender, TextChangedEventArgs e)
    {
        //Psuedocode
        //ObjectViewModel ovm = (sender as Entry).Text.Binding.Source;
    }

The reason I want to do this is to perform validation on "MyString" and change its "MyStringIsValid" property if necessary. My question is how do I do this and if it isn't possible, can you recommend a better approach?

In my real code I have used INotifyPropertyChanged to update the view according to viewModel changes, but I have omitted this for brevity.

Thanks!

Oigeen
  • 25
  • 4
  • 1
    Normally you would validate in the setter of the bound property (MyString). Then you can set the MyStringIsValid property at the same time. Why don't you do that? – Ben Reierson Dec 29 '19 at 21:50
  • @BenReierson I initially tried that but ran into problems because I want my validation to run asynchronously (using Geocoder from Xamarin.Essentials). I looked into implementing some techniques from this [useful post](https://stackoverflow.com/questions/6602244/how-to-call-an-async-method-from-a-getter-or-setter), but honestly it feels like I'm over-complicating something that should be relatively simple. – Oigeen Dec 30 '19 at 00:14
  • hmm, there shouldn't be an issue with running an async validation method from the property setter, but there are always a few ways to do things. – Ben Reierson Dec 31 '19 at 01:22

1 Answers1

1

I guess all you need is a Converter. I don't know why you need to maintain a property for changing the IsVisible based on the validation of a text. The below code works for me for a similar scenario which you mentioned.

<!--Declare the namespace at the top of the XAML-->
xmlns:c="clr-namespace:Demo.Helper"

<!--Register your Converter in the Resources-->
<ContentPage.Resources>
    <ResourceDictionary>
        <c:TextToBoolConverter x:Key="textToSpeechConverter" />
    </ResourceDictionary>
</ContentPage.Resources>

<Entry x:Name="entry1" Text="{Binding ObjectViewModel.MyString}" />
<Label Text="Valid!" IsVisible="{Binding Text, Source={x:Reference entry1}, Converter={StaticResource textToSpeechConverter}}"/>

Below is the converter code which I tested.

public class TextToBoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string stringValue = value?.ToString();
        if (!string.IsNullOrEmpty(stringValue))
            return true;

        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Harikrishnan
  • 1,474
  • 2
  • 11
  • 25
  • Thanks for the reply. Yes the BindingContext is set up correctly to the ViewModel. Actually my "ViewModel" has several instances of "ObjectViewModels" which bind to several Entry controls as above. I've been trying to get the code behind to get the relevant instance of "ObjectViewModel" in order to validate it. I have a feeling there's a simpler way to do this but would appreciate it if you could shed any further light on it. – Oigeen Dec 29 '19 at 10:30
  • 1
    I guess you are looking for a converter to do the trick. If you want to update the visibility of your label based on the entry text, then my edited solution should work fine for you. All you need to do is just declare names for your entries and pass the appropriate names to the IsVisible Binding Source property. – Harikrishnan Dec 29 '19 at 13:06