4

I have a base grid

<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>

which uses the following 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>

How can i capture the "OnWidgetTapped" event on my base xaml class?

OrElse
  • 9,709
  • 39
  • 140
  • 253

5 Answers5

4

I do this usually with a custom bindable property ParentBindingContext in my template:

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); }
    }
}

And then in your page (which contains the template) just set the ParentBindingContext:

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

With that you can access the full BindingContext of your page in your template. The following example of a command shows how the template can bind to a command MyCommand, which is in the BindingContext of the page:

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

But this presupposes that your page has a BindingContext behind (like a ViewModel). This ViewModel then contains the "global" commands for the whole page. These commands (or just methods) can then be accessed by the template, because they know about the BindingContext of the page.

Joehl
  • 3,671
  • 3
  • 25
  • 53
  • Can you please tell what is BasePageTemplate? and i am assigning the template based on some condition via DataTemplateSelector. I have a different templates to show depending on the current Model. where can i set the ParentBindingContext? – Basit ZIa Aug 27 '17 at 11:41
  • The `BasePageTemplate` is the name of the template's class. For the example above it would be `DashboardItemTemplate` – canvee May 10 '19 at 06:45
1

I changed an answer from flow description to the code. The idea is to create ItemTemplate programatically and pass to its constructor the page with list (or grid). Define a function ItemTemplateTapped and call it from template.

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 code behind

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 code behind

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);

    }
}
Yuri S
  • 5,355
  • 1
  • 15
  • 23
  • I must confess I am totally impressed and I wish I could follow the whole flow behind this – OrElse Nov 13 '16 at 22:03
  • I will do some code with grid but cannot exactly reproduce Grial. Is that acceptable for you? – Yuri S Nov 13 '16 at 22:07
  • sure that won't be a problem – OrElse Nov 13 '16 at 22:08
  • Sorry :-) regular grid doesn't have item source and it is not templatable, so my code will be based on ListView but idea is the same – Yuri S Nov 13 '16 at 22:21
  • And if all that is too complicated just use Messenger :-) Subscribe in Page and Fire from template. Though some people don't like to use messenger and try to avoid it at all costs – Yuri S Nov 13 '16 at 23:28
  • @YuriS Why do people try to avoid messenger? – Dennis Schröer Nov 14 '16 at 06:31
  • @Zure From my perspective it is useful in some situations. Here is some discussions. https://xamarinhelp.com/common-misuse-messagingcenter/ There are more in linked in "Xamarin Forms" group – Yuri S Nov 14 '16 at 15:47
  • @OrElse Any of answers worked for you? There is another option to create an event in template and when you create template the page can subscribe to that event. This is about the same as the solution I described above. – Yuri S Nov 14 '16 at 15:49
  • @Zure Hello all. After countless efforts I solved it by using the messenger style. Actually I didn't know the existence of it prior to this post. The only thing that is frightening me, is any memory - performance issues, since I am passing a structure of items within it.. – OrElse Nov 15 '16 at 22:33
0

You just need to implement your OnWidgetTapped method:

void OnWidgetTapped(object sender, System.EventArgs e)
{
    // Do stuff here
}
Dennis Schröer
  • 2,392
  • 16
  • 46
  • I actually want to raise the OnWidgetTapped event in the base grid not within the template itself. How can i accomplish this ? Something like event += new event, into the gridview – OrElse Nov 12 '16 at 14:55
0

If you already defined the tap gesture binding in the XAML code, you don't need to add the TapGestureRecognizer, simply sign your method to an event listener method:

Your XAML:

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

On C# code behind:

public void OnWidgetTapped(object sender, EventArgs args)
{
// do stuff here
}
  • I actually want to raise the OnWidgetTapped event in the base grid not within the template itself. How can i accomplish this ? Something like event += new event, into the gridview – OrElse Nov 12 '16 at 14:54
0

Another solution. If you implemented OnWidgetTapped as was suggested you can use sender.Parent.Parent... till you get to the object you want - grid or page. Cast it to for example EventOnGridPage and then call the function of that object.

Yuri S
  • 5,355
  • 1
  • 15
  • 23