Using a M3 List Api for a single hit

For M3 we have different APIs, most used are probably the list and get APIs. But what if you have a mashup and what you need is in a list API? Well you could just as well use the list API and bind to the first returned item. Or in fact you configure the MIDataService to only return the first result in the list.

Assuming there is an exact match you will get the expected data back. Say that you want to list customers and you pass in Infor, if infor isn’t a valid customer the list API will return whatever customer that comes after alphabetically.

My example will have an entry field for the customer to search for and a button that will trigger the List Event. In a real scenario this would probably be replaced with an event from a standard M3 form, like a CurrentItemChanged on a list or a detail form.

1. Adding the TextBox and the Button to the UI

<StackPanel Orientation="Horizontal"><TextBlock Text="Customer:" VerticalAlignment="center" />
   <TextBox Name="searchText" Width="200" />
      <Button Content="Search" IsDefault="True" Style="{DynamicResource
        styleButtonPrimaryMashup}"/>
</StackPanel>

2. Add a MIPanel and configure it for CRS610MI LstByNumber

3. Before saving I select the Generate Form button and order the fields. If the GenerateButton is not pressed then no XAML for the UI will be generated – only the XAML for the definition of the datasource. There is no roundtrip editing of the UI in the control so keep in mind that manually added converters and styles and stuff will be lost if you edit the control for example if you want to add another field.

4. Click Generate to go to the Generate Content screen

The Generate content screen are the fields that I would like to display in the form. The isVisible flag is for those values that should exist in the form but not be visible. This approach is useful when you have a scenario were for example the key, like CUNO should be in the form but it doesn’t need to be visible but it is needed for further events such as calling an API to update the data.

The result is the XAML for the form.

<m3:MIPanel Name="customer">
    <m3:MIPanel.DataSource>
      <m3:MIDataSource Program="CRS610MI" Transaction="LstByNumber" Type="List" InputFields="CUNO" OutputFields="SMCD,AGPG,TDIN,CORG,COR2" MaxReturnedRecords="1" />
    </m3:MIPanel.DataSource>
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="8" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="16" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="8" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="16" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <Label Content="Organization number 1:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="11" Text="{Binding [CORG]}" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Organization number 2:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="11" Text="{Binding [COR2]}" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Overdue invoice amount:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="15" Text="{Binding [TDIN]}" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Post giro number:" Grid.Row="0" Grid.Column="4" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="10" Text="{Binding [AGPG]}" Grid.Row="0" Grid.Column="6" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Salesperson:" Grid.Row="1" Grid.Column="4" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="10" Text="{Binding [SMCD]}" Grid.Row="1" Grid.Column="6" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
    </Grid>
  </m3:MIPanel>

5. Make sure the panel is entered in a new row by setting Grid.Row=”1”. Now the UI and the data service are configured. All that remains is to define the event that will drive the detail form and to modify the generated bindings since the actual result for a list is a collection and not a specific entry. {Binding [SMCD]} assumes that the DataContext is a single result which it won’t be so we need to manually fix that as well. There is a general difference between using a list or a detail panel. MIListPanel has an Items property with the result and the MIDetailPanel has an Item property. The only reason we added the Detail panel was to generate the XAML with the form. Copy out the Grid with the content above. Now we have to replace the MIPanel with a list.

6. It’s the same configuration and generation but it will generate a ListView as content. Replace the ListView with the grid from above. The control will look like this:

<m3:MIListPanel Name="customer" Grid.Row="1">
    <m3:MIListPanel.DataSource>
      <m3:MIDataSource Program="CRS610MI" Transaction="LstByNumber" Type="List" InputFields="CUNO" OutputFields="CORG,COR2,TDIN,SMCD" />
    </m3:MIListPanel.DataSource>
      <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="8" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="16" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="8" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="16" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <Label Content="Organization number 1:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="11" Text="{Binding [CORG]}" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Organization number 2:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="11" Text="{Binding [COR2]}" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Overdue invoice amount:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="15" Text="{Binding [TDIN]}" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Post giro number:" Grid.Row="0" Grid.Column="4" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="10" Text="{Binding [AGPG]}" Grid.Row="0" Grid.Column="6" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Salesperson:" Grid.Row="1" Grid.Column="4" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="10" Text="{Binding [SMCD]}" Grid.Row="1" Grid.Column="6" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
    </Grid>
  </m3:MIListPanel>

7. Set the correct DataContext. The result for the list is in an Items proeprty. To bind to a single line add the following to the grid.

DataContext="{Binding Items[0], ElementName=customer}"

8.Add the following event to the Button.

<Button Content="Search" IsDefault="True" Style="{DynamicResource styleButtonPrimaryMashup}">
  <Button.CommandParameter>
    <mashup:Events>
      <mashup:Event TargetName="customer" SourceEventName="Click" TargetEventName="List">
        <mashup:Parameter TargetKey="CUNO" Value="{Binding ElementName=searchText, Path=Text}" />
      </mashup:Event>
    </mashup:Events>
  </Button.CommandParameter>
</Button>

9. In my final mashup code I added a list just to validate the data.

<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.ColumnDefinitions>
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>

  <StackPanel Orientation="Horizontal"><TextBlock Text="Customer:" VerticalAlignment="center" /><TextBox Name="searchText" Width="200" />
    <Button Content="Search" IsDefault="True" Style="{DynamicResource styleButtonPrimaryMashup}">
      <Button.CommandParameter>
        <mashup:Events>
          <mashup:Event TargetName="customer" SourceEventName="Click" TargetEventName="List">
            <mashup:Parameter TargetKey="CUNO" Value="{Binding ElementName=searchText, Path=Text}" />
          </mashup:Event>
          <mashup:Event TargetName="customerList" SourceEventName="Click" TargetEventName="List">
            <mashup:Parameter TargetKey="CUNO" Value="{Binding ElementName=searchText, Path=Text}" />
          </mashup:Event>
        </mashup:Events>
      </Button.CommandParameter>
    </Button>
  </StackPanel>
  <m3:MIListPanel Name="customer" Grid.Row="1" Margin="10,30,10,0">
    <m3:MIListPanel.DataSource>
      <m3:MIDataSource Program="CRS610MI" Transaction="LstByNumber" Type="List" InputFields="CUNO" OutputFields="CORG,COR2,TDIN,SMCD,AGPG" />
    </m3:MIListPanel.DataSource>
    <Grid DataContext="{Binding Items[0], ElementName=customer}">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="8" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="16" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="8" />
        <ColumnDefinition Width="200" />
        <ColumnDefinition Width="16" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <Label Content="Organization number 1:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="11" Text="{Binding [CORG]}" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Organization number 2:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="11" Text="{Binding [COR2]}" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Overdue invoice amount:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="15" Text="{Binding [TDIN]}" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Post giro number:" Grid.Row="0" Grid.Column="4" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="10" Text="{Binding [AGPG]}" Grid.Row="0" Grid.Column="6" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
      <Label Content="Salesperson:" Grid.Row="1" Grid.Column="4" HorizontalAlignment="Left" VerticalAlignment="Center" />
      <TextBox MaxLength="10" Text="{Binding [SMCD]}" Grid.Row="1" Grid.Column="6" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
    </Grid>
  </m3:MIListPanel>
  <m3:MIListPanel Name="customerList" Grid.Row="2" Margin="10">
    <m3:MIListPanel.DataSource>
      <m3:MIDataSource Program="CRS610MI" Transaction="LstByNumber" Type="List" InputFields="CUNO" OutputFields="CUNM,CUNO,CORG,COR2,TDIN,AGPG,SMCD" MaxReturnedRecords="1" />
    </m3:MIListPanel.DataSource>
    <ListView ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
      <ListView.View>
        <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
          <GridView.Columns>
            <GridViewColumn Header="Customer number" DisplayMemberBinding="{Binding [CUNO]}" />
            <GridViewColumn Header="Organization number 1" DisplayMemberBinding="{Binding [CORG]}" />
            <GridViewColumn Header="Organization number 2" DisplayMemberBinding="{Binding [COR2]}" />
            <GridViewColumn Header="Overdue invoice amount" DisplayMemberBinding="{Binding [TDIN]}" />
            <GridViewColumn Header="Post giro number" DisplayMemberBinding="{Binding [AGPG]}" />
            <GridViewColumn Header="Salesperson" DisplayMemberBinding="{Binding [SMCD]}" />
          </GridView.Columns>
        </GridView>
      </ListView.View>
    </ListView>
  </m3:MIListPanel>
  <ui:StatusBar Name="StatusBar" Grid.Row="3" Grid.Column="0" />
</Grid>

In this example I demonstrated how to use a list API but bind to the details in a form. Note however that using this above combination might not trigger the correct CurrentItemChanged event when content is loaded. I have not tested but I can imagine that there are issues since the different MI Mashup controls target different purposes and different usage scenarios.

What remains in the example? I generally don’t like the idea that you might get the details for another customer if there is no exact match. Not sure how to solve that. Perhaps we could use the generic property setter event combined with a converter. But a converter has to be a converter that is already part of the LSO.

A good tip if you have issues is to use Fiddler to see exactly what is returned from the API. You could also test the MI transaction in MITest++ (mforms://mitest), a test tool that is available from within Lawson Smart Office.

LSO uses a M3-API-WS and relies on meta data information for successful handling of data. If you have issues with making the request in MITest++ and it works in MITest then the issue is always in the meta data for the MI transactions.

Happy coding!

6 thoughts on “Using a M3 List Api for a single hit

  1. deepm3

    Hi Karin,
    I have a mashup with built-in controls like Label, TextBox, Button. Its a form with TextBox having F4 browse capability. Now I have a Button that needs to execute a Get API transaction without using MIDataPanel or MIListPanel and set the output values to the built-in control form. Any idea how we could do this? Thank you.

    Reply
    1. karinpb Post author

      Hi,
      There is no way to do that whithout using the MIDataPanel. You still need to use the MIDataPanel but that panel does not have to have an UI. You configure the event on the button to call trigger an event on the MIDataPanel. That panel will have the data once it is loaded and you can write a binding to the data. The syntaxt below might work. I don’t have time to do an example right now. But you have to option of binding to the MIDataPanel control (that is hidden) or wrap your content with the control – and you will have the result on the DataContext. Check the API documentation for MIDataPanel. The property is Items or Item – if I remember it correctly. It will contain a list of records or one record.

      Text="{Binding ElementName=miPanel, Path=Item["ITNO"]}"
      
      Reply
      1. deepm3

        Thank you Karin,
        I am already binding to output from Dialog like this <TextBox Name="WarehouseNameTextBox" MaxLength="30" Width="150" MinWidth="150" IsReadOnly="true" IsEnabled="false" VerticalAlignment="Center" Text="{Binding ElementName=WarehouseSearchDialog, Path=CurrentItem[WarehouseName]}

        So how could we bind to another source from MIPanel?

      2. karinpb Post author

        Hi,
        You can only have one binding at the time. What is your scenorio in more detail? What is the data that you would like to get from the API? Perhaps you can have a DetailPanel with one get and one update transaction? Or you could use an event to set the Text Property – then you would set it without changing the existing binding. Check the set property example in the designer or post part of your xaml. Code must be escaped.

  2. deepm3

    Hi Karin,
    Thank you for your comments. My scenario is an enquiry screen with header and details. Header is merely a simple form containing input TextBox with F4 browse functions. Next to these TextBox fields are TextBlock fields holding descriptions and names.
    Ex: Warehouse input field will have warehouse name TextBlock next to it which gets populated either by F4 browse dialog or by hitting Enter key that invokes a custom API validating input fields and returning all these description or names (warehouse name in this case).
    I followed your suggestion of using hidden MIPanel with collapsed state and using event of MIPanel. The custom API that is invoked is actually a “Get” type. However, setting “Get” type does not trap a suitable event after API returns. So I decided to set the type to “Update” and trap UpdateComplete event. In this event I could successfully use SetProperty to set the Text of TextBlock controls. Below code indicates how SetProperty was used to set warehouse name after an API call.

    <m3:MIPanel Name="HeaderCheck">
    <m3:MIPanel.Events>
    <mashup:Events>
    <mashup:Event SourceEventName="UpdateComplete" Target="{mashup:SetProperty ElementName=WarehouseNameTextBox, Path=Text}" SupportsRefresh="False">
    <mashup:Parameter TargetKey="Value" Value="{Binding [WHNM]}" />
    </mashup:Event>
    </mashup:Events>
    </m3:MIPanel.Events>
    <m3:MIPanel.DataSource>
    <m3:MIDataSource Program="ZZZZ01MI" Transaction="CheckHeader" Type="Update" InputFields="CONO,WHLO,ITGR,DPID,STDT,PRNO" OutputFields="ITDS,TX40,WHNM,ITNO,FACI" />
    </m3:MIPanel.DataSource>
    </m3:MIPanel>

    Reply
    1. karinpb Post author

      Hi,
      I’m glad it worked. We have been thinking about adding a CompletedEvent just to be able to track replies but it was very smart of you to find the Update event and thank you for sharing 🙂

      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