lokesh
lokesh

Reputation: 330

How to bind model annotation to a control in .net MAUI XAML content page?

I have model like below

public class Person
{
   [Display(Name = "Name of the Person", Prompt = "Enter your Name")]
   public string Name { get; set; }
}

.net MAUI content Page as below

<StackLayout>
    <Label Text="{Binding DisplayNameAnnotation}"/>
    <Entry Text="{Binding Person.Name}" Placeholder="{Binding DisplayPromptAnnotation}"/>
</StackLayout>

The expected outcome is as shown in the image Sample image

The purpose is to have a common model for asp.net and .net maui with annotations and efcore decorations.Syncfusion's dataform does this by default. We cannot use syncfusion.

DisplayNameAnnotation and DisplayPromptAnnotation are written for illustration only. Binding the Name to the entry control is straight forward. I wanted to bind the corresponding annotations to placeholder or text of another label. This is straight forward in asp.net application with labelfor kind of tags. But, in .net MAUI, I could not able to figure out a way to do it. Can any one point to me in right direction.

Upvotes: 0

Views: 339

Answers (1)

Liqun Shen-MSFT
Liqun Shen-MSFT

Reputation: 8220

Update

Seems that you want to reuse the Converter and you don't want to assign the Type to be only Person. Though we Reflection to GetCustomAttributes, I think we have to know the Type.

One way is to utilize the ConverterParameter. If you want the Converter to be generic, I think you at least have to pass 3 parameters,

1.Namespace name.

2.Class name,

3.Property name,

Then the question comes to how to pass multiple parameters to a Converter. There are several ways to achieve that. One of the easiest ways I think is to use ConverterParameter=Namespace|ClassName|PropertyName and retrieve the corresponding value in Converter using String.Split("|") method.

    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
       
        string[] parameters = ((string)parameter).Split("|");
        string myNamespace = parameters[0];
        string myClassName = parameters[1];
        string myProperty = parameters[2];
        Type myType = Type.GetType(string.Format("{0}.{1}", myNamespace, myClassName), true);      

        MemberInfo prop = myType.GetProperty(myProperty);
        DisplayAttribute[] attr = prop.GetCustomAttributes(typeof(DisplayAttribute)) as DisplayAttribute[];
        if(attr.Length == 0)
        {
            return value;
        }
        else
        {
            return attr[0].GetName();
        }

        //throw new NotImplementedException();
    }

    ...

There is no direct way to bind Display attributes in MAUI. But you could use ValueConverter to achieve that.

Suppose there is a Name Porperty with DisplayAttribute in ViewModel,

public class MainPageViewModel
{
    public Person Person { get; set; } = new Person();

}

public class Person
{
    [Display(Name = "Name of the Person", Prompt = "Enter your Name")]
    public string Name { get; set; } = "Default Name";
}

What we want to do is to use in XAML like the following,

<ContentPage.Resources>
    <local:GetDisplayName x:Key="getDisplayName" />
</ContentPage.Resources>
...
<StackLayout>
    <Label Text="{Binding Person.Name,Converter={StaticResource getDisplayName},ConverterParameter=Name}"/>
    <Entry Text="{Binding Person.Name}" />
</StackLayout>

Then this is our ValueConverter,

public class GetDisplayName : IValueConverter
{
    public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
    {

        MemberInfo prop = typeof(Person).GetProperty((string)parameter);
        DisplayAttribute[] attr = prop.GetCustomAttributes(typeof(DisplayAttribute)) as DisplayAttribute[];
        if(attr.Length == 0)
        {
            return value;
        }
        else
        {
            return attr[0].GetName();
        }

        //throw new NotImplementedException();
    }

    public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

enter image description here

Upvotes: 1

Related Questions