Custom list templates in M3 Mashups

Support for custom list templates in M3 Mashups was added in Smart Office version 10.0.3. The requirement was to be able to display lists in a more compact way, similar to a card view list. The settings dialog for the M3 ListPanel control now have the option to choose two different List styles called Standard and Template. The Template List style lets you to create a custom list template that defines how the list rows are displayed in the list.

The custom list templates can be defined using only the Settings dialog but it is also possible to modify the templates in XAML where you have full control and more options. I will show one example of how to use the Settings dialog to create a custom list template and then show an example with a custom template defined in XAML.

When to use a custom template

There are some limitations with custom list templates that you should be aware of before you start using it. The main difference is that the list column headers are no longer shown so there are no position fields. This means that a list with custom templates is less suited to be the main list in a Mashup. You will probably use another list or some other kind of controls to provide input for the custom template list. You could actually implement your own solution for list positioning with a TextBox a Button and the Apply event, but I’ll leave that as an exercise if your’re interested.

Although there are limitations with custom list templates the positive thing is that the list paging and the context menu for list options still work as before.

Note that the two examples in this post are just stand alone lists to show what is possible and not examples of a complete Mashups.

Creating a custom template in Settings

Before we start with the custom list template I will assume that you have a ListPanel configured with a bookmark for the program you want to use and a Startup event. I have chosen the customer program CRS610 for my example. In the Startup event I have set the CUNO value to blank so that the list starts from the beginning. Test your Mashup with this basic configuration first to make sure that you get some data in the list before starting with the template.

The next step is to change the List style from Standard to Template. When the List style is changed another field called “Template indexes/names” and a Generate button will appear. The new field is used to indicate which list columns you want to use in your template. You can enter a comma separated list of column names or the zero based indexes of the columns. In most cases it is probably best to use the column names but for a specific sorting order / view you could use the column indexes as well. In my example I use the column names and selected the customer number (CUNO), customer name (CUNM) and phone number (PHNO) columns.

M3CTMPL_ListPanelSettings

When you have decided the columns to use click the Generate button. This will show a dialog where you can configure the template to generate. You can configure the widths of the columns, alignment, font size and font weight. If you don’t want to show the column headers as labels you can uncheck Show labels. If you don’t want a separator line you can uncheck Show separator line.

M3CTMPL_GenerateTemplate

When you have configured the template the way you like press the OK button. This will show a confirmation dialog since any existing template will be overwritten. Click Yes and then OK to close the settings dialog.

M3CTMPL_ConfirmTemplate

In the XAML code you will now see a couple of new things. There is a ListStyle attribute set to Template and a TemplateIndexes attribute set to the columns you selected. The TemplateIndexes attribute is only used in the Designer and it has no effect in runtime.

The most interesting part is within the m3:ListPanel.ItemTemplate element. The content of the element is a standard WPF DataTemplate that has been generated using the values you selected in the Generate Template dialog. You can change things manually in the DataTemplate but remember that the changes will be overwritten if you use the Generate template dialog again.

If you know WPF DataTemplates this should familiar but the bindings probably needs some explaining. The data objects for the M3 list are instances of the ListRow class. The ListRow class have two new properties called HeaderByName and ItemByName. Both these properties expose an indexer that accepts a column name or a column index. HeaderByName will return the list column header and ItemByName will return the list cell value.

M3CTMPL_EditorExample1

Run your example and verify that it works. Test different settings in the Generate template dialog to see how it affects the result. You can see how my example looks like below.

M3CTMPL_RunningExample1

Example code

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:Mango.UI.Controls;assembly=Mango.UI" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms">
   <Grid.Resources>
   </Grid.Resources>

   <m3:ListPanel Name="CustomerList" ListStyle="Template" TemplateIndexes="CUNO,CUNM,PHNO">
      <m3:ListPanel.Events>
         <mashup:Events>
            <mashup:Event SourceEventName="Startup" TargetEventName="List">
               <mashup:Parameter TargetKey="OKCONO" />
               <mashup:Parameter TargetKey="OKCUNO" DefaultValue="" />
            </mashup:Event>
         </mashup:Events>
      </m3:ListPanel.Events>

      <m3:ListPanel.Bookmark>
         <m3:Bookmark Program="CRS610" Table="OCUSMA" KeyNames="OKCONO,OKCUNO" SortingOrder="1" />
      </m3:ListPanel.Bookmark>

      <m3:ListPanel.ItemTemplate>
         <DataTemplate>
            <Grid>
               <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="Auto" />
                  <ColumnDefinition Width="6" />
                  <ColumnDefinition Width="*" />
               </Grid.ColumnDefinitions>
               <Grid.RowDefinitions>
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="Auto" />
               </Grid.RowDefinitions>
               <TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding Path=HeaderByName[CUNO]}" HorizontalAlignment="Right" FontWeight="Bold" />
               <TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding Path=ItemByName[CUNO]}" HorizontalAlignment="Left" />
               <TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding Path=HeaderByName[CUNM]}" HorizontalAlignment="Right" FontWeight="Bold" />
               <TextBlock Grid.Column="2" Grid.Row="1" Text="{Binding Path=ItemByName[CUNM]}" HorizontalAlignment="Left" />
               <TextBlock Grid.Column="0" Grid.Row="2" Text="{Binding Path=HeaderByName[PHNO]}" HorizontalAlignment="Right" FontWeight="Bold" />
               <TextBlock Grid.Column="2" Grid.Row="2" Text="{Binding Path=ItemByName[PHNO]}" HorizontalAlignment="Left" />
               <Separator Style="{DynamicResource styleSeparatorHorizontalThin}" Margin="0,4,0,0" Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="3" />
            </Grid>
         </DataTemplate>
      </m3:ListPanel.ItemTemplate>

   </m3:ListPanel>
</Grid>

Creating a custom template in XAML

When creating custom template you can still start with the Generate template dialog. This will give you the correct syntax for the bindings that you want to use in the template. In this example I will use the result of the previous example as a starting point.

The template for this example will not be pretty, it is just a way to show that you can get a list that looks drastically different from the standard list.

The first thing I did was to add an Ellipse control to get some kind of graphical element. Next to the Ellipse I want to show the customer name with a large font size. The default color of the Ellipse and the customer name is set to (almost) black. On the second line I added the customer number with the normal font size. In this example I just used the ItemByName property since I don’t want to show the column headers.

The next thing I did was to add DataTriggers to get some colors in the list. I change the color of the Ellipse and the customer name depending on the status of the customer. Status 12 gets an orange color, status 20 gets green and status 90 gets red. Customers with another status will keep the default color.

M3CTMPL_EditorExample2

Run the example to see how the DataTriggers are applied. In my examples with (bad) test data it looks like this.

M3CTMPL_RunningExample2

This example just scratches the surface of what is possible with custom list templates but I hope it gets you thinking about how you can use it in your own solutions.

Example code

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:Mango.UI.Controls;assembly=Mango.UI" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms">

   <Grid.Resources>
   </Grid.Resources>

   <Grid.RowDefinitions>
      <RowDefinition Height="1*" />
   </Grid.RowDefinitions>

   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="1*" />
   </Grid.ColumnDefinitions>

   <m3:ListPanel Name="CustomerList" ListStyle="Template" TemplateIndexes="CUNO,CUNM,PHNO">
      <m3:ListPanel.Events>
         <mashup:Events>
            <mashup:Event SourceEventName="Startup" TargetEventName="List">
               <mashup:Parameter TargetKey="OKCONO" />
               <mashup:Parameter TargetKey="OKCUNO" DefaultValue="" />
            </mashup:Event>
         </mashup:Events>
      </m3:ListPanel.Events>

      <m3:ListPanel.Bookmark>
         <m3:Bookmark Program="CRS610" Table="OCUSMA" KeyNames="OKCONO,OKCUNO" SortingOrder="1" />
      </m3:ListPanel.Bookmark>

      <m3:ListPanel.ItemTemplate>
         <DataTemplate>

            <Grid Margin="0,0,0,8">
               <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="Auto" />
                  <ColumnDefinition Width="6" />
                  <ColumnDefinition Width="Auto" />
               </Grid.ColumnDefinitions>
               <Grid.RowDefinitions>
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="4" />
                  <RowDefinition Height="Auto" />
               </Grid.RowDefinitions>

               <Ellipse Name="ellipseCustomer" Grid.Column="0" Grid.Row="0" Fill="#111111" Width="20" Height="20" HorizontalAlignment="Left" VerticalAlignment="Center" />
               <TextBlock Name="textBlockCustomerName" Grid.Column="2" Grid.Row="0" Foreground="#111111" FontSize="18" Text="{Binding Path=ItemByName[CUNM]}" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold" />
               <TextBlock Grid.Column="2" Grid.Row="2" Text="{Binding Path=ItemByName[CUNO]}" HorizontalAlignment="Left" />
            </Grid>

            <DataTemplate.Triggers>
               <DataTrigger Binding="{Binding Path=ItemByName[STAT]}" Value="12">
                  <!-- Orange -->
                  <Setter TargetName="ellipseCustomer" Property="Fill" Value="#FFD100" />
                  <Setter TargetName="textBlockCustomerName" Property="Foreground" Value="#FFD100" />
               </DataTrigger>
               <DataTrigger Binding="{Binding Path=ItemByName[STAT]}" Value="20">
                  <!-- Green -->
                  <Setter TargetName="ellipseCustomer" Property="Fill" Value="#1EDB1E" />
                  <Setter TargetName="textBlockCustomerName" Property="Foreground" Value="#1EDB1E" />
               </DataTrigger>
               <DataTrigger Binding="{Binding Path=ItemByName[STAT]}" Value="90">
                  <!-- Red -->
                  <Setter TargetName="ellipseCustomer" Property="Fill" Value="#FF3C1E" />
                  <Setter TargetName="textBlockCustomerName" Property="Foreground" Value="#FF3C1E" />
               </DataTrigger>
            </DataTemplate.Triggers>
         </DataTemplate>
      </m3:ListPanel.ItemTemplate>

   </m3:ListPanel>

</Grid>

8 thoughts on “Custom list templates in M3 Mashups

  1. Essam Agha

    I didn´t get the customer row when I ran the program, I have CUNO in the template indexes/names!
    what did I miss?
    Thank you

    Essam

    Reply
  2. Essam Agha

    Sorry, I need help with “a textbox a buttom and a apply event” they didn´t work together 😦
    plz help!

    Essam

    Reply
    1. norpe Post author

      Unfortunately the Apply event did not work in this scenario, probably something we should support in future versions since it is more efficient for something like this.

      For now you will have to use the List event instead, see example code below.

      <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:Mango.UI.Controls;assembly=Mango.UI" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms">
         <Grid.Resources>
         </Grid.Resources>
      
         <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="1*" />
         </Grid.RowDefinitions>
         <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="1*" />
         </Grid.ColumnDefinitions>
      
         <TextBox Name="textBoxPosition" Grid.Column="0" Margin="10,10,0,0" Width="100" MaxLength="10" CharacterCasing="Upper" VerticalAlignment="Center" HorizontalAlignment="Left" />
         <Button Content="Apply" Grid.Column="1" Margin="10,10,10,0" VerticalAlignment="Center" HorizontalAlignment="Left">
            <Button.CommandParameter>
               <mashup:Events>
                  <mashup:Event TargetName="CustomerList" SourceEventName="Click" TargetEventName="List">
                     <mashup:Parameter SourceKey="CUNO" Value="{Binding Path=Text, ElementName=textBoxPosition}" />
                  </mashup:Event>
               </mashup:Events>
            </Button.CommandParameter>
         </Button>
      
         <m3:ListPanel Name="CustomerList" Margin="10" ListStyle="Template" TemplateIndexes="CUNO,CUNM,PHNO" Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1">
            <m3:ListPanel.Events>
               <mashup:Events>
                  <mashup:Event SourceEventName="Startup" TargetEventName="List">
                     <mashup:Parameter TargetKey="OKCONO" />
                     <mashup:Parameter TargetKey="OKCUNO" DefaultValue="" />
                  </mashup:Event>
               </mashup:Events>
            </m3:ListPanel.Events>
      
            <m3:ListPanel.Bookmark>
               <m3:Bookmark Program="CRS610" Table="OCUSMA" KeyNames="OKCONO,OKCUNO" SortingOrder="1" />
            </m3:ListPanel.Bookmark>
      
            <m3:ListPanel.ItemTemplate>
               <DataTemplate>
                  <Grid>
                     <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="6" />
                        <ColumnDefinition Width="*" />
                     </Grid.ColumnDefinitions>
                     <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                     </Grid.RowDefinitions>
                     <TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding Path=HeaderByName[CUNO]}" HorizontalAlignment="Right" FontWeight="Bold" />
                     <TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding Path=ItemByName[CUNO]}" HorizontalAlignment="Left" />
                     <TextBlock Grid.Column="0" Grid.Row="1" Text="{Binding Path=HeaderByName[CUNM]}" HorizontalAlignment="Right" FontWeight="Bold" />
                     <TextBlock Grid.Column="2" Grid.Row="1" Text="{Binding Path=ItemByName[CUNM]}" HorizontalAlignment="Left" />
                     <TextBlock Grid.Column="0" Grid.Row="2" Text="{Binding Path=HeaderByName[PHNO]}" HorizontalAlignment="Right" FontWeight="Bold" />
                     <TextBlock Grid.Column="2" Grid.Row="2" Text="{Binding Path=ItemByName[PHNO]}" HorizontalAlignment="Left" />
                     <Separator Style="{DynamicResource styleSeparatorHorizontalThin}" Margin="0,4,0,0" Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="3" />
                  </Grid>
               </DataTemplate>
            </m3:ListPanel.ItemTemplate>
      
         </m3:ListPanel>
      
      </Grid>
      
      Reply
    1. norpe Post author

      This is supported with conditional styles in the regular M3 list panels and in Mashups using the ListPanel with the regular templates.

      There is no support for this using the custom list templates in a Mashup. This could be solved with a custom template selector but that would require an SDK feature to implement.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s