简体   繁体   中英

How can I use the Xamarin.Forms.Setter class in my own ContentView (custom control)?

I am creating a ContentView custom control which I named AutoAdaptingView . Basically, it's a grid which can handle two View (FirstContent and SecondContent), and it will automatically put the two View in either two rows or two columns, depending on the orientation, screen height, etc. Now, I want to create two attached BindableProperty named PortraitSetters and LandscapeSetters, which are List<Setter> , so that the consumer of this class can use XAML to declare variations of HorizontalOptions, RequestedHeight and any other relevant property using a list of Setter . That list will be scanned when the orientation changes, and it will use Reflection to set all the properties that need to be setted. The problem is that if I use such list, it won't compile because it cannot convert from string to BindableProperty .

Here's my BindableProperty declaration:

        //
        public static readonly BindableProperty PortraitSettersProperty = BindableProperty.CreateAttached(
            "PortraitSetters",
            typeof(List<Setter>),
            typeof(AutoAdaptingView),
            null
        );

        public static List<Setter> GetPortraitSetters(BindableObject target)
        {
            return (List<Setter>)(target as View).GetValue(PortraitSettersProperty);
        }

        public static void SetPortraitSetters(BindableObject target, List<Setter> value)
        {
            (target as View).SetValue(PortraitSettersProperty, value);
        }

        //
        public static readonly BindableProperty LandscapeSettersProperty = BindableProperty.CreateAttached(
            "LandscapeSetters",
            typeof(List<Setter>),
            typeof(AutoAdaptingView),
            null
        );

        public static List<Setter> GetLandscapeSetters(BindableObject target)
        {
            return (List<Setter>)(target as View).GetValue(LandscapeSettersProperty);
        }

        public static void SetLandscapeSetters(BindableObject target, List<Setter> value)
        {
            (target as View).SetValue(LandscapeSettersProperty, value);
        }

Here's an example of how it would be used:

<ctrl:AutoAdaptingView>
    <ctrl:AutoAdaptingView.FirstContent>
        <StackLayout Orientation="Vertical"
                     Spacing="16">

            <ctrl:AutoAdaptingView.PortraitSetters>
                <Setter Property="HorizontalOptions" Value="Center"/>
                <Setter Property="VerticalOptions" Value="Start"/>
                <Setter Property="Margin" Value="16, 100, 16, 16"/>
            </ctrl:AutoAdaptingView.PortraitSetters>

            <ctrl:AutoAdaptingView.LandscapeSetters>
                <Setter Property="HorizontalOptions" Value="Center"/>
                <Setter Property="VerticalOptions" Value="Center"/>
                <Setter Property="Margin" Value="16"/>
            </ctrl:AutoAdaptingView.LandscapeSetters>

            <!-- actual content here -->

And here's the problem:

Cannot convert "HorizontalOptions" into Xamarin.Forms.BindableProperty

Obviously I don't expect XAML to magically understand that the Property field refers to a StackLayout BindableProperty, but just in the same way that the Style class has a TargetType property that permits it to automatically convert the property name string to the actual BindableProperty object, there should be a way that permits me to implement the same.

A solution I thought about was to create my own Setter class that, instead of a BindableProperty object, it only takes a property name (since that is what I actually need in the implementation), but then wouldn't I need to create a converter in order to transform the values (ie "16, 100, 16, 16" to new Margin(16, 100, 16, 16) )?

The simplest solution would be to use an event instead, that the consumer will handle in the code behind, but this would cost the advantages of code-resource separation.

You could define your styles in App.xaml (Global styling)

<Style x:Key="portraitStyle" TargetType="custom:LabelEntry">
   <Setter Property="HorizontalOptions" Value="Center"/>
            <Setter Property="VerticalOptions" Value="Start"/>
            <Setter Property="Margin" Value="16, 100, 16, 16"/>
</Style>

and, in your View Binding

Style="{Binding YourProperty , Converter={ StaticResource ConvertStyleKey }}"

With a converter for:

public class ConvertStyle : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        valueType = (YourModel)value
        if (valueType.YourProperty)
        {
            return Application.Current.Resources["portraitStyle"] as Style;
        }
        else
        {
            //other style
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM