我正在尝试使用Xamarin Forms实现相当于WPF无外观控件。那就是:
我正在使用这种方法,以便控件可以公开一些可绑定的属性,这些属性可以由其用户设置,属性来自其ControlTemplate
TemplateBind的元素。它运行良好,UI按预期加载。
但是,我现在遇到了从UI子节点处理事件的问题。例如,我的ControlTemplate
中有一些网格,我想处理它们上的Tapped事件。
我尝试了以下内容:
<Grid.GestureRecognizers>
,其中TappedCommand
是控件公开的命令。这会在应用程序加载时抛出InvalidOperationException,并显示“无效状态”或其他内容。EventTrigger
的{{1}}和自定义ExecuteCommandAction
。我永远不会调用TriggerAction<View>
的Invoke。ExecuteCommandAction
事件处理程序。这是有效的,但处理程序在App.xaml.cs中,所以不是很有帮助,我需要它在控件本身。我还可以考虑尝试在模板中声明Tapped
并从控件引用它,然后以编程方式向其添加x:Name
,但我不知道在哪里做这个。在WPF中有一个TappedGestureRecognizer
方法,通过名称查看模板中的子项是“安全的”。 Xamarin Forms中有类似的东西吗?
非常感谢任何其他建议!
稍后编辑,这是代码:
OnApplyTemplate()
这是App.xaml public class NextPrevDateSelector : ContentView
{
public NextPrevDateSelector ()
{
this.ShowPreviousDayCommand = new Command(() =>
{
/// This is where I'd like to handle the taps on the
/// element (Grid or Button or whatever) inside the template
/// which should change the date to the previous day. This
/// need not be a Command, if I could register an event handler
/// to the Tapped event that'd also be fine
});
}
// These events would be subscribed to by users of the control.
// They'd probably be commands, not events, but I put events here to
// keep the code small.
public event EventHandler PreviousDaySelected;
public event EventHandler NextDaySelected;
// This property can be used by users of the control to customize how the text inside the control looks like, the elements in the control's template will TemplateBind to this
public static readonly BindableProperty TextStyleProperty = BindableProperty.Create(
propertyName: "TextStyle",
returnType: typeof(Style),
declaringType: typeof(NextPrevDateSelector),
defaultValue: null);
public Style TextStyle
{
get { return (Style)GetValue(TextStyleProperty ); }
set { SetValue(TextStyleProperty , value); }
}
public ICommand ShowPreviousDayCommand { get; private set; }
}
ResourceDictionary
和控制模板
<Style TargetType="dateSelector:NextPrevDateSelector">
<Setter Property="ControlTemplate" Value="{StaticResource DateSelectorTemplate}" />
</Style>
我需要知道什么时候点击prevDayButton,nextDayButton和中心按钮。如上所述,我首先尝试了这个:
<ControlTemplate x:Key="DateSelectorTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid x:Name="prevDayButton" Grid.Column="0" Padding="20,0,20,0" HorizontalOptions="Start">
<Label Grid.Column="0" Text="<" Style="{TemplateBinding TextStyle}" />
</Grid>
<Grid Grid.Column="1" HorizontalOptions="Center">
<Label Text="Today etc" Style="{TemplateBinding TextStyle}" />
</Grid>
<Grid x:Name="nextDayButton" Grid.Column="2" Padding="20,0,20,0" HorizontalOptions="End">
<Label Text=">" Style="{TemplateBinding TextStyle}" />
</Grid>
</Grid>
</ControlTemplate>
这会引发app初始化。接下来我尝试了这个:
<Grid x:Name="prevDayButton" Grid.Column="0" Padding="20,0,20,0" HorizontalOptions="Start">
<Label Grid.Column="0" Text="<" Style="{TemplateBinding TextStyle}" />
<Grid.GestureRecognizers>
<TapGestureRecognizer Command={TemplateBinding ShowPreviousDayCommand}/>
</Grid.GestureRecognizers>
</Grid>
...其中ExecuteCommandAction是<Grid x:Name="prevDayButton" Grid.Column="0" Padding="20,0,20,0" HorizontalOptions="Start">
<Label Grid.Column="0" Text="<" Style="{TemplateBinding TextStyle}" />
<Grid.GestureRecognizers>
<TapGestureRecognizer>
<EventTrigger Event="Tapped">
<behaviors:ExecuteCommandAction/>
</EventTrigger>
</TapGestureRecognizer>
</Grid.GestureRecognizers>
</Grid>
,但从不调用它的Invoke方法。所以我离开了为“按钮”添加一个普通的事件处理程序,但我无法在XAML中添加它,因为处理程序需要在我的控制中,我无法将其添加到我的控件中因为我不能找到一种方法来获取对按钮的引用,以便我可以为它们添加手势识别器。
我希望代码能让问题更清晰。