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.
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.
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.
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.
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.
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.
Run the example to see how the DataTriggers are applied. In my examples with (bad) test data it looks like this.
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>
Thanks for this example. Really helpful.
Thanx, thanx and thanx!
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
The problem is solved! thank you!
Sorry, I need help with “a textbox a buttom and a apply event” they didn´t work together 😦
plz help!
Essam
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.
How do you apply the style based on a date? I need the style to take place if a start date is more than 2 days old.
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.
Hi,
I have a question,
how do you create a customer list that contains columns from 2 potential columns.
for example CRS610 & CRS315.
and then use that list in a mashup?
kind regards.
Qasim
Hello,
I’m trying to make a custom list to use instead of PMS100. I want to bring the Deliver Number from MHDISH to MWOHED and then add the related options 31 & 32 from MHDISH so I can release the order for Allocation, Picking, Report Operations, and Report Receipt from the same screen. I’ve connected the tables and can see the delivery number (I only have 1 material to issue at this point so only 1 delivery number) but when I try to use the related option 31 or 32 H5 dumps and I get an ‘Abnormal End’. Can you only add related options from the base table?