0

I am confused in XAML namespace declaration. Please help to clarify my case. I have class BooleanToObjectConverter : IValueConverter in CoTraveller namespace:

public class EmailValidatorBehavior : Behavior<Entry>
{
    const string digitRegex = @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
        @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";

static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(EmailValidatorBehavior), false);
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;

static readonly BindablePropertyKey IsVisiblePropertyKey = BindableProperty.CreateReadOnly("IsVisible", typeof(bool), typeof(EmailValidatorBehavior), false);
public static readonly BindableProperty IsVisibleProperty = IsVisiblePropertyKey.BindableProperty;

public bool IsValid
{
    get { return (bool)base.GetValue(IsValidProperty); }
    private set { base.SetValue(IsValidPropertyKey, value); }
}

public bool IsVisible
{
    get { return (bool)base.GetValue(IsVisibleProperty); }
    private set { base.SetValue(IsVisiblePropertyKey, value); }
}

protected override void OnAttachedTo(Entry entry)
{
    entry.TextChanged += OnEntryTextChanged;
    base.OnAttachedTo(entry);
}

protected override void OnDetachingFrom(Entry entry)
{
    entry.TextChanged -= OnEntryTextChanged;
    base.OnDetachingFrom(entry);
}

void OnEntryTextChanged(object sender, TextChangedEventArgs e)
{
    if (e.NewTextValue.Length > 0)
    {
        IsVisible = true;
        Entry entry = (Entry)sender;
        IsValid = Regex.IsMatch(e.NewTextValue, digitRegex);

        if (IsValid) // Check only if we have a valid email
        {
            // Here we validate if the email contains our requirements
            String email = entry.Text;
            int pos = email.IndexOf("@"); // Exclude the domain
            string username = email.Substring(0, pos);
            if (username.Contains(FRIEND) || username.Contains(FRIENDS))
            {
                IsValid = true;
            }
            else
                IsValid = false;
        }
    }
    else
        IsVisible = false;
}

public class BooleanToObjectConverter<Image> : IValueConverter
{
    public Image FalseObject { set; get; }

    public Image TrueObject { set; get; }

    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        return (bool)value ? this.TrueObject : this.FalseObject;
    }

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

    public object ConvertBack(object value, Type targetType,
                              object parameter, CultureInfo culture)
    {
        return ((Image)value).Equals(this.TrueObject);
    }

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

}

I want to use FalseObject and TrueObject properties in App resources like:

<Application 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    x:Class="CoTraveller.RegistrationPage"
   xmlns:local="clr-namespace:CoTraveller">
    <Application.Resources>
        <!-- Application resource dictionary -->
        <ResourceDictionary>
            <local:BooleanToObjectConverter x:Key="boolToStyleImage" 
x:TypeArguments="Style">
                <local:BooleanToObjectConverter.FalseObject>
                    <Style TargetType="Image">
                        <Setter Property="HeightRequest" Value="24" />
                        <Setter Property="Source" 
Value="your_wrong_image_here.png" />
                    </Style>
                </local:BooleanToObjectConverter.FalseObject>

                <x:BooleanToObjectConverter.TrueObject>
                    <Style TargetType="Image">
                        <Setter Property="HeightRequest" Value="24" />
                        <Setter Property="Source" 
Value="your_correct_image_here.png" />
                    </Style>
                </x:BooleanToObjectConverter.TrueObject>
            </local:BooleanToObjectConverter>
        </ResourceDictionary>
    </Application.Resources>
</Application>

but have error: Severity Code Description Project File Line Suppression State Error XLS0415 The attachable property 'FalseObject' was not found in type 'BooleanToObjectConverter'. CoTraveller App.xaml 11

What is the problem?

Jahangirova
  • 23
  • 1
  • 1
  • 5
  • https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/attached-properties – Jason Jul 22 '18 at 20:15
  • In WPF I derive the valueconverter from DependencyObject so I can use DependencyProperties in the converter. Those you can bind to. See: https://stackoverflow.com/questions/48539313/valueconverter-with-properties – Emond Jul 22 '18 at 20:23

1 Answers1

0

Derive from DependencyObject in order to be able to use the bindable DependencyProperties:

public class BooleanToObjectConverter: DependencyObject, IValueConverter
{
    public Image FalseObject
    {
        get
        {
            return (Image)GetValue(FalseObjectProperty);
        }
        set
        {
            SetValue(FalseObjectProperty, value);
        }
    }

    public static readonly DependencyProperty FalseObjectProperty =
        DependencyProperty.Register(
            "FalseObject", 
            typeof(Image), 
            typeof(BooleanToObjectConverter<Image>), 
            new PropertyMetadata(null));

    public Image TrueObject
    {
        get
        {
            return (Image)GetValue(TrueObjectProperty);
        }
        set
        {
            SetValue(TrueObjectProperty, value);
        }
    }

    public static readonly DependencyProperty TrueObjectProperty =
        DependencyProperty.Register(
            "TrueObject",
            typeof(Image), 
            typeof(BooleanToObjectConverter<Image>), 
            new PropertyMetadata(null));

    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        return (bool)value ? this.TrueObject : this.FalseObject;
    }

    public object ConvertBack(object value, Type targetType,
                              object parameter, CultureInfo culture)
    {
        return ((Image)value).Equals(this.TrueObject);
    }
}

Side note: The use of the generic here doesn't make a lot of sense so I removed it.

If the original intention was to do use an actual generic type see: Generic Type in Xaml Resources because it is not that straight forward to specify a generic type argument for entries in a resources dictionary.

Emond
  • 50,210
  • 11
  • 84
  • 115