[英]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
.我正在创建一个名为AutoAdaptingView
的ContentView
自定义控件。 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
.基本上,它是一个可以处理两个View
(FirstContent 和 SecondContent)的网格,它会根据方向、屏幕高度等自动将两个View
放在两行或两列中。 现在,我想创建两个附加的BindableProperty
命名为 PortraitSetters 和 LandscapeSetters,它们是List<Setter>
,以便此类的使用者可以使用 XAML 使用Setter
列表声明 HorizontalOptions、RequestedHeight 和任何其他相关属性的变体。 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
.问题是,如果我使用这样的列表,它将无法编译,因为它无法从string
转换为BindableProperty
。
Here's my BindableProperty declaration:这是我的 BindableProperty 声明:
//
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.显然,我不希望 XAML 神奇地理解Property
字段指的是StackLayout
BindableProperty,但就像Style
类具有TargetType
属性一样,它允许它自动将属性名称字符串转换为实际的BindableProperty
对象,应该有一种方法可以让我实现相同的方法。
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)
)?我想到的一个解决方案是创建我自己的 Setter 类,而不是BindableProperty
对象,它只需要一个属性名称(因为这是我在实现中实际需要的),但是我不需要创建转换器为了转换值(即"16, 100, 16, 16"
到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)您可以在 App.xaml 中定义您的样式(全局样式)
<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
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.