Add reference to ResourceDictionary to custom dataTemplate class

alexestralexestr Member ✭✭

I have a list that will be listing different types of appointments. Based on the type, I was hoping to use a DataTemplateSelector and create several different DataTemplates. As each is fairly large, wanted to create a class that i could reference in the Listview as such:

</ResourceDictionary>
    <local:StatusImgConverter x:Key="StatusImgConverter" />
    <local:AppointmentDataTemplateSelector x:Key="appointmentDataTemplateSelector" 
                                          JobTemplate="{StaticResource jobTemplate}" 
                                          GeneralTemplate="{StaticResource generalTemplate}" />
</ResourceDictionary>

<ListView>
    <ListView.ItemTemplate "{StaticResource personDataTemplateSelector}" />
</ListView>

Where JobTemplate.xaml uses a converter referenced in the file with the ListView

<DataTemplate xmlns="http://xamarin.com/schemas/2014/forms" 
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="MyApp.CustomContentViews.DataTemplates.JobTemplate">
<ViewCell>
    <StackLayout >
        <Image Source="phone.png">
            <Image.GestureRecognizers>
                <TapGestureRecognizer Command="{???}"
                                      CommandParameter="{Binding Source={x:Reference jobid}, Path=Text}"/>
            </Image.GestureRecognizers>
        </Image>            
        <Image  Source="{Binding Status, Converter={??? How do i get StatusImgConverter ???}}"/>                
    </StackLayout>
</ViewCell>

Ultimately I will have 4 templates, and the first one at least is rather long, so I don't want to just define them all in a single xaml file for the page. Is there any way to do what I am trying?

Best Answer

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai

    You can move these DataTemplates to App.xaml and use them in page.xaml. As the follows
    App.xaml

    <Application.Resources>
        <ResourceDictionary>
                    <DataTemplate x:Key="validPersonTemplate">
            ...
            </DataTemplate>
        </ResourceDictionary>
        </ResourceDictionary>
    </Application.Resources>
    

    page.xaml

    <StackLayout Margin="20">
            <Label Text="ListView with a DataTemplateSelector" FontAttributes="Bold" HorizontalOptions="Center" />
            <ListView x:Name="listView" Margin="0,20,0,0" ItemTemplate="{StaticResource personDataTemplateSelector}" />
    </StackLayout>
    
  • alexestralexestr Member ✭✭

    Will this allow me to use the Converters I reference in the page.xaml?

    Since (as of now) I am only using the templates on one page, I just put it all in page.xaml, I just wanted to avoid having a single monster xaml file. Which putting it all in app.xaml doesn't really fix. Thanks though.

  • TaylorDTaylorD USMember ✭✭✭
    edited March 13

    You can separate your ViewCell code in your DataTemplates into separate Xaml files. You will then need to add the namespace correctly to the top of your page.xaml file to reference them correctly.

    Also, your converter will need to either be defined in the App.xaml or in your new ViewCell files in a <StackLayout.Resources> tag.

    The reason for putting the converter in the StackLayout.Resources is because ViewCell's don't have a resources tag.

    ViewCell Example File

    <ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="MyApp.CustomContentViews.DataTemplates.JobTemplate">
        <StackLayout>
            <StackLayout.Resources>
                <local:StatusImgConverter x:Key="StatusImgConverter" />
            </StackLayout.Resources>
    
            <Image Source="phone.png">
                <Image.GestureRecognizers>
                    <TapGestureRecognizer Command="{???}"
                                          CommandParameter="{Binding Source={x:Reference jobid}, Path=Text}"/>
                </Image.GestureRecognizers>
            </Image>            
            <Image  Source="{Binding Status, Converter={StaticResource StatusImgConverter}}"/>
        </StackLayout>
    </ViewCell>
    

    *Make sure to import the 'local' namespace for your converter at the top of the ViewCell file

    page.xaml

    </ResourceDictionary>
        <DataTemplate x:Key="generalTemplate">
            <local:MyViewCell />
        </DataTemplate>
        <DataTemplate x:Key="jobTemplate">
            <local:MyViewCell2 />
        </DataTemplate>
    
        <local:AppointmentDataTemplateSelector x:Key="appointmentDataTemplateSelector" 
                                              JobTemplate="{StaticResource jobTemplate}" 
                                              GeneralTemplate="{StaticResource generalTemplate}" />
    </ResourceDictionary>
    
  • alexestralexestr Member ✭✭

    Okay, I think that will work. Is there a reason I would not want to define my converters in the app.xaml? Seems like it would be simpler to define them once in app.xaml rather than at the top of each page I use them. I guess the only reason I haven't done this, is because the examples I followed on converters all define them in each separate page.

  • TaylorDTaylorD USMember ✭✭✭
    edited March 13
    I would suggest placing them in your App.xaml. That’s what my project is currently doing and it works well.
  • JarvanJarvan Member, Xamarin Team Xamurai

    Try to use ContentView. You can put each template in a separate ContentView and quote the ContentView which you want in page.xaml.

    View1.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="DataTemplate_.View1">
        <ContentView.Resources>
            <DataTemplate x:Key="validPersonTemplate">
                <ViewCell>
                   ...
                </ViewCell>
            </DataTemplate>
        </ContentView.Resources>
    </ContentView>
    

    page.xaml

    <?xml version="1.0" encoding="UTF-8"?>~~~~
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:DataTemplate_"
                 x:Class="DataTemplate_.Page1">
        <ContentPage.Resources>
            <local:View1 x:Key="validPersonTemplate"/>
        </ContentPage.Resources>
        <StackLayout Margin="20">
            <Label Text="ListView with a DataTemplateSelector" FontAttributes="Bold" HorizontalOptions="Center" />
            <ListView x:Name="listView" Margin="0,20,0,0" ItemTemplate="{StaticResource validPersonTemplate}" />
        </StackLayout>
    </ContentPage>
    
  • TaylorDTaylorD USMember ✭✭✭

    @yelinzh Putting an extra ContentView around the ViewCell and DataTemplate adds an extra layer of view that isn't needed. Also, a ListView's ItemTemplate needs a DataTemplate with a ViewCell.

    Using the ContentView as the ItemTemplate would either not compile or exception at runtime.

  • JarvanJarvan Member, Xamarin Team Xamurai

    I‘ve deployed the code I post successfully , you can take a try.

  • TaylorDTaylorD USMember ✭✭✭
    edited March 14

    I copied and pasted the code you posted and it builds and runs like you said, but the ItemTemplate is not applied. It uses the default TextCell template.

    Even though it builds and is deployed, the xaml compiler is showing errors that the data types don't match.

    Also, if you bypass using a separate file with your example and consolidate it into a single file, the app fails to compile.

  • JarvanJarvan Member, Xamarin Team Xamurai

    just as the image shows

  • alexestralexestr Member ✭✭

    @yelinzh , I like putting it in it's own file, but why not inherit directly from DataTemplate? Seems to be the same functionally, but reduces complexity, no?

  • TaylorDTaylorD USMember ✭✭✭
    edited March 14

    @yelinzh Where is the green text in the labels in the cell? I'm also not sure where the orange is coming from because I don't see that color in your ViewCell template.

    @alexestr You can define them as a DataTemplate in a separate file and that should work the same way. I usually just put them as a ViewCell only and then that allows me to put special logic for animations or UI and for extra BindableProperties if they are needed in the cell.

    For example if you would like to use the cell multiple times (i.e. a DataTemplateSelector) and each DataTemplate use the same cell, if you want different Label text colors or want other ViewCell properties different, having it only as a DataTemplate, might make it difficult to do that.

    I haven't tested that example or logic with a DataTemplate itself, but using only a ViewCell type works well for that type of logic.

  • alexestralexestr Member ✭✭

    @TaylorD , would that also allow me to reference a Command that wasn't part of the List<MyClass>? I have an element with it's own gesture recognizer that calls a command. When I was only using a single DataTemplate, I had to define the Command in somewhere else in the xaml outside of the listView and use x:Reference' andPath(which seems rather clumsy). When I pulled theDataTemplate` into its own file, that little hack no longer worked and I couldn't figure out how a solution.

Sign In or Register to comment.