如何从基类中捕获被点击的项目(位于模板中)的事件?

Posted

技术标签:

【中文标题】如何从基类中捕获被点击的项目(位于模板中)的事件?【英文标题】:How can i capture the event of a tapped item (located in a template) from the base class? 【发布时间】:2017-03-24 10:49:37 【问题描述】:

我有一个基础网格

<Grid Grid.Row="1" Grid.Column="1" x:Name="GridName">
            <StackLayout Orientation="Vertical">
                <art:GridOptionsView ItemsSource="Binding Items" >
                    <art:GridOptionsView.ItemTemplate>
                        <DataTemplate>
                            <uikit:DashboardItemTemplate />
                        </DataTemplate>
                    </art:GridOptionsView.ItemTemplate>
                </art:GridOptionsView>
            </StackLayout>
        </Grid>

它使用以下 DashboardItemTemplate

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
        BackgroundColor="White">
    <ContentView.Content>
        <Grid Padding="0">
            <StackLayout VerticalOptions="Center" HorizontalOptions="Center" Orientation="Vertical" Spacing="10">
                <Grid>
                    <Label Text="" Style="StaticResource FontIcon" HorizontalTextAlignment="Center" Opacity="1" FontSize="130" TextColor="Binding BackgroundColor" VerticalOptions="Center" HorizontalOptions="Center" IsVisible="Binding Source=x:Reference Root, Path=ShowiconColoredCircleBackground" />
                    <Label Text="Binding Icon" Style="StaticResource FontIcon" Opacity="1" TextColor="White" VerticalOptions="Center" HorizontalOptions="Center" />
                </Grid>
                <Label Text="Binding Name" TextColor="Binding Source=x:Reference Root, Path=TextColor" FontSize="14" HorizontalTextAlignment="Center">
                </Label>
            </StackLayout>
        </Grid>
    </ContentView.Content>
    <ContentView.GestureRecognizers>
        <TapGestureRecognizer Tapped="OnWidgetTapped" />
    </ContentView.GestureRecognizers>
</ContentView>

如何在我的基础 xaml 类中捕获“OnWidgetTapped”事件?

【问题讨论】:

你在使用 Grial 组件吗? 【参考方案1】:

我通常使用模板中的自定义可绑定属性 ParentBindingContext 来执行此操作:

public class MyTemplate : ContentPage

    public static BindableProperty ParentBindingContextProperty = BindableProperty.Create(nameof(ParentBindingContext), 
        typeof(object), typeof(BasePageTemplate));


    public object ParentBindingContext
    
        get  return GetValue(ParentBindingContextProperty); 
        set  SetValue(ParentBindingContextProperty, value); 
    

然后在你的页面(包含模板)中设置ParentBindingContext

<DataTemplate>
    <template:MyTemplate ParentBindingContext="Binding BindingContext, Source=x:Reference Name=MyPageName" />
</DataTemplate>

这样您就可以在模板中访问您页面的完整BindingContext。下面的命令示例显示了模板如何绑定到页面的BindingContext 中的命令MyCommand

Command="Binding ParentBindingContext.MyCommand, Source=x:Reference Name=MyTemplatePageName"

但这前提是你的页面后面有一个BindingContext(就像一个ViewModel)。然后,此 ViewModel 包含整个页面的“全局”命令。然后模板可以访问这些命令(或只是方法),因为它们知道页面的BindingContext

【讨论】:

你能告诉我什么是BasePageTemplate吗?我正在通过 DataTemplateSelector 根据某些条件分配模板。根据当前模型,我有不同的模板要显示。我在哪里可以设置 ParentBindingContext? BasePageTemplate 是模板类的名称。对于上面的示例,它将是 DashboardItemTemplate【参考方案2】:

我将答案从流程描述更改为代码。这个想法是以编程方式创建 ItemTemplate 并将带有列表(或网格)的页面传递给它的构造函数。定义一个函数 ItemTemplateTapped 并从模板中调用它。

EventOnGridPage

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonRendererDemo.EventOnGridPage">

 <ListView x:Name="listView" >
</ListView>           
</ContentPage>

EventOnGridPage 后面的代码

public partial class EventOnGridPage : ContentPage


    public EventOnGridPage()
    
        InitializeComponent();

       listView.ItemsSource = new List<Contact>
       
           new Contact  Name = "Kirti",Status = "True",
           new Contact  Name = "Nilesh",Status = "False"
       ;

        listView.ItemTemplate = new DataTemplate(loadTemplate);
    

    private object loadTemplate()
    
        return new ViewCell()  View = new EventOnGridTemplate(this) ;
    

    public void ItemTemplateTapped(string name)
    
        DisplayAlert("ItemTemplateTapped", name, "OK");
    

EventOnGridTemplate xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonRendererDemo.EventOnGridTemplate"
             BackgroundColor="Green">

  <Label Text="Binding Name" x:Name="myLabel"></Label>

</ContentView>

EventOnGridTemplate 后面的代码

public partial class EventOnGridTemplate

    EventOnGridPage parent;

    public EventOnGridTemplate(EventOnGridPage parent)
    
        this.parent = parent;

        InitializeComponent();

        var tapGestureRecognizer = new TapGestureRecognizer();
        tapGestureRecognizer.Tapped += TapGestureRecognizer_Tapped;
        myLabel.GestureRecognizers.Add(tapGestureRecognizer);

    

    private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
    
         parent.ItemTemplateTapped(myLabel.Text);

    

【讨论】:

我必须承认我印象非常深刻,我希望我能跟随这背后的整个流程 我会用网格做一些代码,但不能完全重现 Grial。你能接受吗? 确保不会有问题 Sorry :-) 常规网格没有项目源且不可模板化,因此我的代码将基于 ListView 但思路相同 如果这一切都太复杂了,只需使用 Messenger :-) 在页面中订阅并从模板中触发。虽然有些人不喜欢使用 Messenger 并尽量避免使用它【参考方案3】:

如果您已经在 XAML 代码中定义了点击手势绑定,则无需添加 TapGestureRecognizer,只需将您的方法签名为事件侦听器方法即可:

您的 XAML:

<ContentView.GestureRecognizers>
    <TapGestureRecognizer Tapped="OnWidgetTapped" />
</ContentView.GestureRecognizers>

关于后面的 C# 代码:

public void OnWidgetTapped(object sender, EventArgs args)

// do stuff here

【讨论】:

我实际上想在基本网格中引发 OnWidgetTapped 事件,而不是在模板本身内。我怎样才能做到这一点?像事件 += 新事件,进入网格视图【参考方案4】:

你只需要实现你的OnWidgetTapped 方法:

void OnWidgetTapped(object sender, System.EventArgs e)

    // Do stuff here

【讨论】:

我实际上想在基本网格中引发 OnWidgetTapped 事件,而不是在模板本身内。我怎样才能做到这一点?像事件 += 新事件,进入网格视图【参考方案5】:

另一种解决方案。如果您按照建议实施 OnWidgetTapped,您可以使用 sender.Parent.Parent... 直到您到达您想要的对象 - 网格或页面。将其转换为例如 EventOnGridPage,然后调用该对象的函数。

【讨论】:

以上是关于如何从基类中捕获被点击的项目(位于模板中)的事件?的主要内容,如果未能解决你的问题,请参考以下文章

如何从基类中获取派生类名

从基类函数派生的类容器

如何使用 C++ 中的模板编程从基类创建派生类?

从基类派生类中 C++ 向量的可访问性

从基类调用派生类中的函数

Typescript - 从基类中的静态方法实例化子类,使用 args 并引用其他静态方法