Mashup – The “new modal Dialog window”

Previously this year I wrote a post regarding popups.  And now there is something so much better…
What I didn’t know then, was that there already existed a modal dialog window for exactly this kind of behaviour I wanted within the mashup in later release.
We recently had an upgrade of our environment, and there I suddenly was… Maybe it’s just me not keeping up with all the new features, and I guess there are others of you out there who also don’ know.
So I’d like to share a small example. You can also find an example in the mashup designer under common controls, if you have it.

What I find really nice, is that the dialog windows are own .xaml files, which means it’s being added really quickly if I have to re-use it somewhere else.

This is how it can look, in this case I used it for supplier search, which often can be good to have many places. It writes back from the Dialog.xaml to the primary.xaml.

SupplierDialogBox2

Below is the code that had to be added in the primary mashup. I also added a ‘F4” gesture to open it.


<StackPanel Grid.Row="1" Grid.Column="3">
                  <mashup:Dialog Name="SupplierMyDialog" Uri="SupplierDialogBox.xaml" WindowHeight="600" WindowWidth="540" HorizontalAlignment="Left" />
                  <TextBox Name="Supplier" Text="{Binding ElementName=SupplierMyDialog, Path=CurrentItem[Supplier]}" MinWidth="80" MaxWidth="80">
                     <TextBox.InputBindings>           
                        <KeyBinding Key="F4" Command="mashup:MashupInstance.MashupCommand">          
                           <KeyBinding.CommandParameter>             
                              <mashup:Events>
                                 <mashup:Event SourceEventName="Click" TargetName="SupplierMyDialog" Debug="True">
                                    <mashup:Parameter TargetKey="SupplierNumber" Value="{Binding ElementName=Supplier, Path=Text}" />
                                 </mashup:Event>
                              </mashup:Events>          
                           </KeyBinding.CommandParameter>       
                        </KeyBinding>  
                     </TextBox.InputBindings> 
                  </TextBox>   
  </StackPanel>

And here is the complete code for the DialogBox itself.  The close button will target the supplier field with the text input.

Grid Height="600" Width="540" 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" xmlns:clr="clr-namespace:System;assembly=mscorlib" xmlns:Services="clr-namespace:Mango.Services;assembly=Mango.Core" xmlns:ps="clr-namespace:PF.Client.Mashup;assembly=PF.Client">
   <Grid.Resources>
      <mashup:CurrentItemValue x:Key="CurrentItemValue" />
   </Grid.Resources>

   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="540" />
   </Grid.ColumnDefinitions>
   <Grid.RowDefinitions>
      <RowDefinition Height="80" />
      <RowDefinition Height="400" />
      <RowDefinition Height="50" />
      <RowDefinition Height="Auto" />
   </Grid.RowDefinitions>

   <GroupBox Style="{DynamicResource styleGroupLineMashup}">
      <Grid Margin="0,0,0,8">
         <Grid.ColumnDefinitions>
            <ColumnDefinition Width="60" />
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="80" />
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
            <RowDefinition Height="32" />
         </Grid.RowDefinitions>

         <TextBlock Text="Supplier:" Grid.Column="0" />
         <StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="1">
            <mashup:Dialog Name="SupplierMyDialog" Uri="SupplierDialogBox.xaml" Grid.Column="0" Grid.Row="0">
               </mashup:Dialog>         
            <TextBox Name="SupplierNumber" MinWidth="120" MaxWidth="120" HorizontalAlignment="Left" MaxLength="18" Text="" />

         </StackPanel>

         <Button Name="Button" Grid.Column="2" Content="Search">
            <Button.CommandParameter>
               <mashup:Events>
                  <mashup:Event TargetName="ItemMasterSupplierListBrowse" SourceEventName="Click" TargetEventName="Search" Debug="True">
                     <mashup:Parameter TargetKey="Query" Value="{Binding Path=Text, ElementName=SupplierNumber}" />
                  </mashup:Event>
               </mashup:Events>
            </Button.CommandParameter>
         </Button>
      </Grid>
   </GroupBox>

   <m3:ListPanel Name="ItemMasterSupplierListBrowse" Grid.Row="1" EnablePositionFields="False" EnableSortingOrder="False">
      <m3:ListPanel.Events>
         <mashup:Events>
            <mashup:Event SourceEventName="Startup">
               <mashup:Parameter TargetKey="IDCONO" />
               <mashup:Parameter TargetKey="IDSUNO" />
            </mashup:Event>

            <mashup:Event SourceName="ItemMasterSupplierListBrowse" SourceEventName="CurrentItemChanged" Target="{mashup:SetProperty ElementName=SupplierNumber, Path=Text}" Debug="True">
               <mashup:Parameter SourceKey="SUNO" TargetKey="Value" />
            </mashup:Event>
         </mashup:Events>
      </m3:ListPanel.Events>
      <m3:ListPanel.Bookmark>
         <m3:Bookmark Program="CRS620" Table="CIDMAS" KeyNames="IDCONO,IDSUNO" SortingOrder="1" IncludeStartPanel="True" />
      </m3:ListPanel.Bookmark>
   </m3:ListPanel>

   <Button Content="Close" Grid.Row="2">
      <Button.CommandParameter>
         <mashup:Events>
            <mashup:Event SourceEventName="Click" TargetEventName="Close">
               <mashup:Parameter TargetKey="Supplier" Value="{Binding ElementName=SupplierNumber, Path=Text}" />
            </mashup:Event>
         </mashup:Events>
      </Button.CommandParameter>
   </Button>
   
   <ui:StatusBar Name="StatusBar" Grid.Row="3" Grid.Column="0" />
</Grid>

Hope it can be to any help.

Regards
Ken Eric

 

Command & Control a Mashup from an M3 program

Here’s an illustration of how to Command & Control a Mashup from an M3 program with a Smart Office Script, for example to launch a Mashup, to set values in a Mashup, to attach event handlers, to get values from the Mashup, and to close the Mashup. I learned this technique from norpe’s MashupBrowse post.

This is useful to add functionality in a Mashup where XAML alone is not sufficient.

You can attach the script to an M3 program, via Tools > Personalize > Scripts, via Tools > Personalize > Shortcut, or you can execute a stand-alone script.

Steps

First, create and deploy a simple Hello World Mashup (no values nor event handlers, to illustrate the point):

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <StackPanel>
        <Label Name="lblMessage" Content="Message" />
        <TextBox Name="txtValue" />
        <Button Name="btnOK" Content="OK" />
    </StackPanel>
</Grid>

1 2

Then, create a script that starts the Mashup:

var uri : String = "mashup:///?BaseUri=HelloWorld.mashup&RelativeUri=HelloWorld.xaml";
var task : Task = new Task(uri);
var handler : RunnerStatusChangedEventHandler = Mashup_OnStatusChanged;
DashboardTaskService.Current.LaunchTask(task, null, handler);

Then, get a reference to the Mashup:

function Mashup_OnStatusChanged(sender : Object, e : RunnerStatusChangedEventArgs) {
    if (e.NewStatus == RunnerStatus.Running) {
        // the Mashup is starting
        var runner : Runner = e.Runner;
    } else if (e.NewStatus == RunnerStatus.Closed) {
        // the Mashup is closing
    }
}

Then, set values in the Mashup:

txtValue = runner.Host.HostContent.FindName("txtValue");
txtValue.Text = "Hello World!";

Then, attach event handlers:

var btnOK : Button = runner.Host.HostContent.FindName("btnOK");
btnOK.add_Click(Mashup_OnBtnOK);

Result

And here’s the result, the Mashup launched, the value “Hello World!” set in the TextBox, the Click event handler added to the button, and the value of the TextBox retrieved back, all that commanded & controlled from the Script, which would not have been all possible with XAML alone:

3

Source code

Here’s the complete source code:

import System;
import System.Windows;
import System.Windows.Controls;
import Mango.Services;
import Mango.UI.Core;
import Mango.UI.Services;

package MForms.JScript {

class HelloWorldCC {
    var debug;
    var txtValue : TextBox;
    public function Init(element : Object, args : Object, controller : Object, debug : Object) {
        try {
            this.debug = debug;
            // launch the Mashup
            var uri : String = "mashup:///?BaseUri=HelloWorld.mashup&RelativeUri=HelloWorld.xaml";
            var task : Task = new Task(uri);
            var handler : RunnerStatusChangedEventHandler = Mashup_OnStatusChanged;
            DashboardTaskService.Current.LaunchTask(task, null, handler);
        } catch (ex : Exception) {
            debug.WriteLine(ex);
        }
    }
    function Mashup_OnStatusChanged(sender : Object, e : RunnerStatusChangedEventArgs) {
        try {
            if (e.NewStatus == RunnerStatus.Running) {
                // the Mashup is starting
                debug.WriteLine("Mashup is starting");
                var runner : Runner = e.Runner;
                // set values in the Mashup
                txtValue = runner.Host.HostContent.FindName("txtValue");
                txtValue.Text = "Hello World!";
                // attach an event handler to the Mashup
                var btnOK : Button = runner.Host.HostContent.FindName("btnOK");
                btnOK.add_Click(Mashup_OnBtnOK);
            } else if (e.NewStatus == RunnerStatus.Closed) {
                // the Mashup is closing
                debug.WriteLine("Mashup is closing");
            }
        } catch (ex : Exception) {
            debug.WriteLine(ex);
        }
    }
    function Mashup_OnBtnOK(sender : Object, e : RoutedEventArgs) {
        try {
            // get values from the Mashup
            MessageBox.Show(txtValue.Text);
        } catch (ex : Exception) {
            debug.WriteLine(ex);
        }
    }
}
}

Finally

Norpe’s code is more complete and you should implement its features in your script as well. For example norpe’s script checks if there is already an open instance of the Mashup, it can control the Mashup with keyboard shortcuts, it puts values back in the M3 panel, it closes the Mashup, it detaches event handlers, and it does cleanup.

That’s it!

Mashup/LES – Related search and changing view while searching.

I accidently discovered a while back that I could use the TargetKey to set views and sorting orders.
This was followed up by another small indecent, which led to another discovery.
Did you know that you are able change the view after a LES search has been performed and keep the current hits?
I will also share how you can perform a related search with LES from a mashup. ( I will not share how to do all the setup, it’s primary just getting the query right)
When combing all these, I believe you can create quite a powerful tool.

Setting the sorting order:

Very simple, but for some unknown.  Just use the TargetKey to set the value.

<mashup:Event TargetName=”MMS200″ SourceEventName=”Click” TargetEventName=”Apply”>
<mashup:Parameter TargetKey=”WWQTTP” Value=”5″ />
</mashup:Event>

Changing the view can be done in multiple ways, here is an example where it’s done from a ComboBox.

<ComboBox Name="ItemMasterChangeView" MinWidth="85" MinHeight="20" MaxWidth="85" MaxHeight="70" Margin="5">
             <mashup:Event.SelectionChanged>
                <mashup:Events>
                   <mashup:Event SourceEventName="SelectionChanged" TargetName="MMS200" TargetEventName="Apply">
                      <mashup:Event.Conditions>
                         <mashup:Conditions>
                            <mashup:Condition TargetKey="Value" SourceValue="{Binding ElementName=ItemMasterChangeView, Path=SelectedIndex}" TargetValue="1" Operator="Equal" />
                         </mashup:Conditions>
                      </mashup:Event.Conditions>
                      <mashup:Parameter TargetKey="WWFACI" Value="100" />
                      <mashup:Parameter TargetKey="WWWHLO" Value="100" />
                      <mashup:Parameter TargetKey="WOPAVR" Value="{Binding ElementName=ONHAND, Path=Content}" />
                   </mashup:Event>

                   <mashup:Event SourceEventName="SelectionChanged" TargetName="MMS200" TargetEventName="Apply">
                      <mashup:Event.Conditions>
                         <mashup:Conditions>
                            <mashup:Condition TargetKey="Value" SourceValue="{Binding ElementName=ItemMasterChangeView, Path=SelectedIndex}" TargetValue="2" Operator="Equal" />
                         </mashup:Conditions>
                      </mashup:Event.Conditions>
                      <mashup:Parameter TargetKey="WWFACI" Value="100" />
                      <mashup:Parameter TargetKey="WWWHLO" Value="100" />
                      <mashup:Parameter TargetKey="WOPAVR" Value="{Binding ElementName=WHS, Path=Content}" />
                   </mashup:Event>
                </mashup:Events>
             </mashup:Event.SelectionChanged>

             <ComboBoxItem Name="BLANK" Content="" />
             <ComboBoxItem Name="ONHAND" Content="ONHAND" />
             <ComboBoxItem Name="WHS" Content="WHS" />
          </ComboBox>

NOTE: CHANGING SORTING ORDER OR VIEW MIGHT GIVE YOU A FATAL ERROR IN SOME OF THE PREVIOUS VERSIONS OF M3.
I don’t know which version the fix came in, but we recently had a upgrade of our environment and it now runs without problem, so far.
However, if you receive an error message, try setting the sorting order with filter 1 or higher, for some strange reason it only used to crash if the filter was set to 0.

Related search – creating the string.

There might be other ways to do this, so if you solved this previously in any other way I hope you are willing to share.
I will show you two different ways you can concatenate text to get the string you need.

1. Provide input to RespText, and using the MultiBinding will get yourself a string looking like this:
related:[ITEM_RESP(“input”)]:

<TextBox Name="RespText"  Text=""   />
<TextBox Name="RespDummy1" Text="related:[ITEM_RESP(&quot;"  Visibility="Hidden" />
  <TextBox Name="RespDummy2" Text="&quot;)]" Visibility="Hidden" />

    <TextBox Name="ItemRespSearch"  Visibility="Hidden">
       <TextBox.Text>
          <MultiBinding StringFormat="{}{0}{1}{2}">
             <Binding ElementName="RespDummy1" Path="Text" />
             <Binding ElementName="RespText" Path="Text" />
             <Binding ElementName="RespDummy2" Path="Text" />
          </MultiBinding>
       </TextBox.Text>
    </TextBox>

2. The other way is using the run command to concatenate.
This was unknown for me until a week ago, but Heiko was nice and shared it .

In the end, both will give you the same output.

</pre>
<TextBox Name="ItemTypeText" Text=""  />

<TextBlock Name="ItemTypeSearch" Visibility="Hidden">
       <TextBlock.Inlines>
         <Run Text="related:[ITEM_ITTY(&quot;" />
         <Run Text="{Binding ElementName=ItemTypeText,Path=Text}" />
         <Run Text="&quot;)]" />
       </TextBlock.Inlines>
     </TextBlock>

You have to add the string query to the TargetKey itself. If you put it as the value you might get some bad output.
You can set the TargetKey to “Query” and the string as value, but that will kill all your other inputs.

<Button Content="Search" Margin="0,0,0,0" Style="{DynamicResource styleButtonPrimaryMashup}">
             <Button.CommandParameter>
                <mashup:Events>
                   <mashup:Event SourceEventName="Click" TargetName="MMS200" TargetEventName="Search">
                      <mashup:Parameter TargetKey="FUDS" Value="{Binding Path=Text, ElementName=NameText}" />
                       <mashup:Parameter TargetKey="{Binding Path=Text, ElementName=ItemRespSearch}" Value="{Binding Path=Text, ElementName=ItemRespCheck}" />
                       <mashup:Parameter TargetKey="{Binding Path=Text, ElementName=ItemTypeSearch}" Value="{Binding Path=Text, ElementName=ItemTypeCheck}" />
                 </mashup:Event>

As you can see I am binding some values.
If the Value is blank the search will not be performed, so I’m just using this to check for any input.

If there is any input to the “RespText” the value will be set to ‘;’ .
You can use standard mashup conditions instead of the MultiDataTrigger as shown below.

<TextBox Name="ItemRespCheck" Visibility="Hidden">
       <TextBox.Style>
       <Style x:Key="ItemRespCheck" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
          <Setter Property="Text" Value=";" />
          <Style.Triggers>
             <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                   <Condition Binding="{Binding ElementName=RespText, Path=Text}" Value="" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Text" Value="" />
             </MultiDataTrigger>
          </Style.Triggers>
       </Style>
    </TextBox.Style>
    </TextBox>

And the final string query will be like this if you provide input to all 3.

FUDS:(A*) related:[ITEM_RESP(“141254”)]:(;) related:[ITEM_ITTY(“031”)]:(;)
If you are trying and failing with this, I strongly recommand using Fiddler or similar to see what output the mashup sends.

Attached is a full sample containing both the related search and changing view/sorting orders option.
You probably have to change some of the static values I’ve added to make it work.

<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="30" />
       <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal">
          <TextBlock Text="Name:" />
          <TextBox Name="NameText" MaxWidth="80" MinWidth="80" />
          <TextBlock Text="Item responsible:" />
          <TextBox Name="RespText" Text="" MaxWidth="80" MinWidth="80" />
          <TextBlock Text="Item Type:" />
          <TextBox Name="ItemTypeText" Text="" MaxWidth="80" MinWidth="80" />

          <Button Content="Search" Margin="0,0,0,0" Style="{DynamicResource styleButtonPrimaryMashup}">
             <Button.CommandParameter>
                <mashup:Events>
                   <mashup:Event SourceEventName="Click" TargetName="MMS200" TargetEventName="Search">
                      <mashup:Parameter TargetKey="FUDS" Value="{Binding Path=Text, ElementName=NameText}" />
                         <mashup:Parameter TargetKey="{Binding Path=Text, ElementName=ItemRespSearch}" Value="{Binding Path=Text, ElementName=ItemRespCheck}" />
                          <mashup:Parameter TargetKey="{Binding Path=Text, ElementName=ItemTypeSearch}" Value="{Binding Path=Text, ElementName=ItemTypeCheck}" />
                   </mashup:Event>

                      <mashup:Event TargetName="MMS200" SourceEventName="Click" TargetEventName="Apply">
                      <mashup:Event.Conditions>
                         <mashup:Conditions>
                            <mashup:Condition SourceValue="{Binding Path=Text, ElementName=RespText}" TargetValue="" Operator="Equal" />
                         </mashup:Conditions>
                      </mashup:Event.Conditions>
                      <mashup:Parameter TargetKey="WWQTTP" Value="7" />
                   </mashup:Event>

                      <mashup:Event TargetName="MMS200" SourceEventName="Click" TargetEventName="Apply">
                      <mashup:Event.Conditions>
                         <mashup:Conditions>
                            <mashup:Condition SourceValue="{Binding Path=Text, ElementName=RespText}" TargetValue="" Operator="NotEqual" />
                         </mashup:Conditions>
                      </mashup:Event.Conditions>
                      <mashup:Parameter TargetKey="WWQTTP" Value="5" />

                   </mashup:Event>

                </mashup:Events>
             </Button.CommandParameter>
          </Button>

          <TextBlock Text="View" HorizontalAlignment="Right" />

          <ComboBox Name="ItemMasterChangeView" MinWidth="85" MinHeight="20" MaxWidth="85" MaxHeight="70" Margin="5">
             <mashup:Event.SelectionChanged>
                <mashup:Events>
                   <mashup:Event SourceEventName="SelectionChanged" TargetName="MMS200" TargetEventName="Apply">
                      <mashup:Event.Conditions>
                         <mashup:Conditions>
                            <mashup:Condition TargetKey="Value" SourceValue="{Binding ElementName=ItemMasterChangeView, Path=SelectedIndex}" TargetValue="1" Operator="Equal" />
                         </mashup:Conditions>
                      </mashup:Event.Conditions>
                      <mashup:Parameter TargetKey="WWFACI" Value="100" />
                      <mashup:Parameter TargetKey="WWWHLO" Value="100" />
                      <mashup:Parameter TargetKey="WOPAVR" Value="{Binding ElementName=ONHAND, Path=Content}" />
                   </mashup:Event>

                   <mashup:Event SourceEventName="SelectionChanged" TargetName="MMS200" TargetEventName="Apply">
                      <mashup:Event.Conditions>
                         <mashup:Conditions>
                            <mashup:Condition TargetKey="Value" SourceValue="{Binding ElementName=ItemMasterChangeView, Path=SelectedIndex}" TargetValue="2" Operator="Equal" />
                         </mashup:Conditions>
                      </mashup:Event.Conditions>
                      <mashup:Parameter TargetKey="WWFACI" Value="100" />
                      <mashup:Parameter TargetKey="WWWHLO" Value="100" />
                      <mashup:Parameter TargetKey="WOPAVR" Value="{Binding ElementName=WHS, Path=Content}" />
                   </mashup:Event>
                </mashup:Events>
             </mashup:Event.SelectionChanged>
             <ComboBoxItem Name="BLANK" Content="" />
             <ComboBoxItem Name="ONHAND" Content="ONHAND" />
             <ComboBoxItem Name="WHS" Content="WHS" />

          </ComboBox>

    </StackPanel>

    <TextBox Name="RespDummy1" Text="related:[ITEM_RESP(&quot;" Grid.Row="0" Visibility="Hidden" />
    <TextBox Name="RespDummy2" Text="&quot;)]" Visibility="Hidden" />

    <TextBox Name="ItemRespSearch" Grid.Row="0" Grid.Column="3" Visibility="Hidden">
       <TextBox.Text>
          <MultiBinding StringFormat="{}{0}{1}{2}">
             <Binding ElementName="RespDummy1" Path="Text" />
             <Binding ElementName="RespText" Path="Text" />
             <Binding ElementName="RespDummy2" Path="Text" />
          </MultiBinding>
       </TextBox.Text>
    </TextBox>

    <TextBlock Name="ItemTypeSearch" Visibility="Hidden">
       <TextBlock.Inlines>
         <Run Text="related:[ITEM_ITTY(&quot;" />
         <Run Text="{Binding ElementName=ItemTypeText,Path=Text}" />
         <Run Text="&quot;)]" />
       </TextBlock.Inlines>
     </TextBlock>

       <TextBox Name="ItemRespCheck" Visibility="Hidden">
       <TextBox.Style>
       <Style x:Key="ItemRespCheck" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
          <Setter Property="Text" Value=";" />
          <Style.Triggers>
             <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                   <Condition Binding="{Binding ElementName=RespText, Path=Text}" Value="" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Text" Value="" />
             </MultiDataTrigger>
          </Style.Triggers>
       </Style>
    </TextBox.Style>
    </TextBox>

       <TextBox Name="ItemTypeCheck" Visibility="Hidden">
       <TextBox.Style>
       <Style x:Key="ItemTypeCheck" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
          <Setter Property="Text" Value=";" />
          <Style.Triggers>
             <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                   <Condition Binding="{Binding ElementName=ItemTypeText, Path=Text}" Value="" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Text" Value="" />
             </MultiDataTrigger>
          </Style.Triggers>
       </Style>
    </TextBox.Style>
    </TextBox>

    <m3:ListPanel Name="MMS200" Grid.Row="1" IsListHeaderVisible="True" IsListHeaderExpanded="True">
       <m3:ListPanel.Events>
          <mashup:Events>
             <mashup:Event SourceEventName="Startup">
                <mashup:Parameter TargetKey="MBCONO" />
                <mashup:Parameter TargetKey="MBWHLO" />
                <mashup:Parameter TargetKey="MBITNO" />
                <mashup:Parameter TargetKey="WWFACI" Value="100" />
                <mashup:Parameter TargetKey="WWWHLO" Value="100" />
                <mashup:Parameter TargetKey="WWQTTP" Value="5" />
             </mashup:Event>
          </mashup:Events>
       </m3:ListPanel.Events>
       <m3:ListPanel.Bookmark>
          <m3:Bookmark Program="MMS200" Table="MITBAL" KeyNames="MBCONO,MBWHLO,MBITNO" FieldNames="WWFACI,WWHLO,WOPAVR,WWQTTP" />
       </m3:ListPanel.Bookmark>
    </m3:ListPanel>

 </Grid>

Regards
Ken Eric

Mashup – Adding a ContextMenu to the ListView

This week I will show you how you can add a ContextMenu to your ListView.
This is one of these small things that sometimes takes quite some time to figure out.
My major problem with getting the ContextMenu to work in the ListView was to get the actually ‘Click’ working.

Today I will provide you with a working .xaml sample containing some of the basic options from MMS001 using bookmark URI’s.
Related Options , Change, Copy, Delete, Display and Links.
You probably have to set your own values to ITGR and CONO to get it to run.
I also added a little bit of styling, in case this is unknown to some of you.

Here is a snapshot of the result:

ContextMenu

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



 <m3:MIListPanel Name="MMS200MIList">
       <m3:MIListPanel.Events>
          <mashup:Events>
             <mashup:Event SourceEventName="Startup">
                <mashup:Parameter TargetKey="ITGR" Value="03.01" />
             </mashup:Event>
          </mashup:Events>
       </m3:MIListPanel.Events>
       <m3:MIListPanel.DataSource>
          <m3:MIDataSource Program="MMS200MI" Transaction="LstItmByItmGr" Type="List" InputFields="ITGR" OutputFields="ITNO,ITTY,INDI" MaxReturnedRecords="20" />
       </m3:MIListPanel.DataSource>

       <ListView Name="MMS200MIListView" ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">

          <ListView.ContextMenu>
             <ContextMenu>

                <MenuItem Header="Related options">
                   <MenuItem.Style>
                      <Style x:Key="Triggers" TargetType="{x:Type MenuItem}">
                         <Style.Triggers>
                            <Trigger Property="MenuItem.IsMouseOver" Value="true">
                               <Setter Property="Foreground" Value="Red" />
                            </Trigger>
                         </Style.Triggers>
                      </Style>
                   </MenuItem.Style>

                   <MenuItem Header="Material plan" Command="mashup:MashupInstance.MashupCommand">
                      <MenuItem.CommandParameter>
                         <mashup:Events>
                            <mashup:Event SourceEventName="Click" LinkUri="mforms://bookmark?program=MMS001&amp;tablename=MITMAS&amp;keys=MMCONO%2c{CONO}%2cMMITNO%2c{ITNO}%2b%2b%2b%2b%2b%2b%2b%2b%2b&amp;option=34&amp;panel=E&amp;name=MMS001%2fE+Bookmark&amp;source=MForms">
                               <mashup:Parameter TargetKey="ITNO" Value="{Binding [ITNO]}" />
                               <mashup:Parameter TargetKey="CONO" Value="001" />
                            </mashup:Event>
                         </mashup:Events>
                      </MenuItem.CommandParameter>
                   </MenuItem>

                </MenuItem>

                <MenuItem Header="Change" Command="mashup:MashupInstance.MashupCommand">
                   <MenuItem.Style>
                      <Style x:Key="Triggers" TargetType="{x:Type MenuItem}">
                         <Setter Property="FontWeight" Value="Bold" />
                      </Style>
                   </MenuItem.Style>
                   <MenuItem.CommandParameter>
                      <mashup:Events>
                         <mashup:Event SourceEventName="Click" LinkUri="mforms://bookmark?program=MMS001&amp;tablename=MITMAS&amp;keys=MMCONO%2c{CONO}%2cMMITNO%2c{ITNO}%2b%2b%2b%2b%2b%2b%2b%2b%2b&amp;option=2&amp;panel=E&amp;name=MMS001%2fE+Bookmark&amp;source=MForms">
                            <mashup:Parameter TargetKey="ITNO" Value="{Binding [ITNO]}" />
                            <mashup:Parameter TargetKey="CONO" Value="001" />
                         </mashup:Event>
                      </mashup:Events>
                   </MenuItem.CommandParameter>
                </MenuItem>

                <MenuItem Header="Copy" Command="mashup:MashupInstance.MashupCommand">
                   <MenuItem.CommandParameter>
                      <mashup:Events>
                         <mashup:Event SourceEventName="Click" LinkUri="mforms://bookmark?program=MMS001&amp;tablename=MITMAS&amp;keys=MMCONO%2c{CONO}%2cMMITNO%2c{ITNO}%2b%2b%2b%2b%2b%2b%2b%2b%2b&amp;option=3&amp;panel=E&amp;name=MMS001%2fE+Bookmark&amp;source=MForms">
                            <mashup:Parameter TargetKey="ITNO" Value="{Binding [ITNO]}" />
                            <mashup:Parameter TargetKey="CONO" Value="001" />
                         </mashup:Event>
                      </mashup:Events>
                   </MenuItem.CommandParameter>
                </MenuItem>

                <MenuItem Header="Delete" Command="mashup:MashupInstance.MashupCommand">
                   <MenuItem.CommandParameter>
                      <mashup:Events>
                         <mashup:Event SourceEventName="Click" LinkUri="mforms://bookmark?program=MMS001&amp;tablename=MITMAS&amp;keys=MMCONO%2c{CONO}%2cMMITNO%2c{ITNO}%2b%2b%2b%2b%2b%2b%2b%2b%2b&amp;option=4&amp;panel=E&amp;name=MMS001%2fE+Bookmark&amp;source=MForms">
                            <mashup:Parameter TargetKey="ITNO" Value="{Binding [ITNO]}" />
                            <mashup:Parameter TargetKey="CONO" Value="001" />
                         </mashup:Event>
                      </mashup:Events>
                   </MenuItem.CommandParameter>
                </MenuItem>

                <MenuItem Header="Display" Command="mashup:MashupInstance.MashupCommand">
                   <MenuItem.CommandParameter>
                      <mashup:Events>
                         <mashup:Event SourceEventName="Click" LinkUri="mforms://bookmark?program=MMS001&amp;tablename=MITMAS&amp;keys=MMCONO%2c{CONO}%2cMMITNO%2c{ITNO}%2b%2b%2b%2b%2b%2b%2b%2b%2b&amp;option=5&amp;panel=E&amp;name=MMS001%2fE+Bookmark&amp;source=MForms">
                            <mashup:Parameter TargetKey="ITNO" Value="{Binding [ITNO]}" />
                            <mashup:Parameter TargetKey="CONO" Value="001" />
                         </mashup:Event>
                      </mashup:Events>
                   </MenuItem.CommandParameter>
                </MenuItem>

                <MenuItem Header="Links">
                   <MenuItem Header="https://thibaudatwork.wordpress.com" Command="mashup:MashupInstance.MashupCommand">
                      <MenuItem.CommandParameter>
                         <mashup:Events>
                            <mashup:Event SourceEventName="Click" LinkUri="https://thibaudatwork.wordpress.com" LinkIsExternal="True">
                                     </mashup:Event>
                         </mashup:Events>
                      </MenuItem.CommandParameter>
                   </MenuItem>

                </MenuItem>
             </ContextMenu>
          </ListView.ContextMenu>

          <ListView.View>
             <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
                <GridView.Columns>
                   <GridViewColumn Header="Item:" DisplayMemberBinding="{Binding [ITNO]}" />
                   <GridViewColumn Header="Item type:" DisplayMemberBinding="{Binding [ITTY]}" />
                   <GridViewColumn Header="Lot ctrl:" DisplayMemberBinding="{Binding [INDI]}" />
                </GridView.Columns>
             </GridView>
          </ListView.View>
       </ListView>
    </m3:MIListPanel>

    <ui:StatusBar Name="StatusBar" Grid.Row="1" Grid.Column="0" />
 </Grid>

Regards
Ken Eric

Mashup – GridView and CellTemplate

Today I will share some of my experience with the GridView in combination with MIListPanel and MIPanel. It’s a pretty simple solution, but I spent quite some time myself getting it to work the first time, so I hope it’s worth sharing.

My case scenario was to work with multiple lines. I wanted to be able to edit and update in a more “practical” way than having to select a line and then edit from a different panel followed by clicking a button. Sometimes it can be feel to “slow”, and sometimes it just takes too much space.

What I tried to do, was to create an all-in-one solution, by using the GridViewColumn.CellTemplate and actually open the cell in the GridView for editing and adding a button for update. It takes less space, and when processing multiple lines, it sure does feel a lot more user friendly than some of my previous solutions when I first started working with mashup.

The .xaml sample will look something like this:
GridView-Example1

The list is based on CRS620MI, LstSuppliers. The button is connected to the CRS620MI, UpdSupplier. Using the GridViewColumn.CellTemplate will allow you to create a DataTemplate inside the cell, and I think you can do pretty much anything you want when working with DataTemplate.

Here is also a few different scenarios as well using the same method.

Example one is built for speed, when you need to repeat the same task multiple times based on a list.

GridView-Example2

Example two allows you to provide more input. In this case I built a popup inside the CellTemplate. To learn how to create the popup see my previous post .


<TabItem Header="Attached items">
 <StackPanel>

    <m3:MIListPanel Name="MOS256List">
                <m3:MIListPanel.Events>
                   <mashup:Events>
                      <mashup:Event SourceEventName="CurrentItemChanged" SourceName="MMS240List2">
                         <mashup:Parameter TargetKey="MTRL" SourceKey="ITNO" />
                         <mashup:Parameter TargetKey="SERN" SourceKey="SERN" />
                         <mashup:Parameter TargetKey="EXPA" Value="Y" />
                      </mashup:Event>
                   </mashup:Events>
                </m3:MIListPanel.Events>
                <m3:MIListPanel.DataSource>
                   <m3:MIDataSource Program="MOS256MI" Transaction="LstAsBuildLevel" Type="List" InputFields="MTRL,SERN" OutputFields="MTRL,SERN,CFGL,ITNO,SER2,ITDS,LVLS,TX40,MES1,MES2,MES3,MES4,MVA1,MVA2,MVA3,MVA4,STAT" MaxReturnedRecords="50" />
                </m3:MIListPanel.DataSource>

                <ListView ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
                   <ListView.View>
                      <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
                         <GridView.Columns>
                            <GridViewColumn Header="Lvl:" DisplayMemberBinding="{Binding [LVLS]}" />
                            <GridViewColumn Header="Configuration:" DisplayMemberBinding="{Binding [CFGL]}" />
                            <GridViewColumn Header="Position:" DisplayMemberBinding="{Binding [TX40]}" />
                            <GridViewColumn Header="S/N" DisplayMemberBinding="{Binding [SER2]}" />
                            <GridViewColumn Header="Item" DisplayMemberBinding="{Binding [ITNO]}" />
                            <GridViewColumn Header="Descripton:" DisplayMemberBinding="{Binding [ITDS]}" />
                            <GridViewColumn Header="Days:" DisplayMemberBinding="{Binding [MVA1]}" />
                            <GridViewColumn Header="Runs:" DisplayMemberBinding="{Binding [MVA2]}" />
                            <GridViewColumn Header="Hours:" DisplayMemberBinding="{Binding [MVA3]}" />
                            <GridViewColumn Header="Remove">
                               <GridViewColumn.CellTemplate>
                                  <DataTemplate>
                                     <StackPanel>
                                        <ToggleButton Name="button">
                                           <ToggleButton.Template>
                                              <ControlTemplate TargetType="ToggleButton">
                                                 <TextBlock Text="Remove" Foreground="#FFE10101" TextDecorations="Underline" />
                                              </ControlTemplate>
                                           </ToggleButton.Template>
                                        </ToggleButton>

                                        <Popup IsOpen="{Binding IsChecked, ElementName=button, Mode=OneWay}" Width="300" Height="200" Popup.StaysOpen="False">
                                           <Border Background="White" BorderBrush="Black" BorderThickness="2">
                                              <Grid>
                                                 <Grid.RowDefinitions>
                                                    <RowDefinition Height="200" />
                                                 </Grid.RowDefinitions>
                                                 <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="300" />
                                                 </Grid.ColumnDefinitions>
                                                 <StackPanel>
                                                    <GroupBox Header="Remove unit" Style="{DynamicResource styleGroupLineMashup}">
                                                       <Grid Margin="0,0,0,8">
                                                          <Grid.ColumnDefinitions>
                                                             <ColumnDefinition Width="100" />
                                                             <ColumnDefinition Width="200" />
                                                          </Grid.ColumnDefinitions>
                                                          <Grid.RowDefinitions>
                                                             <RowDefinition Height="32" />
                                                             <RowDefinition Height="32" />
                                                             <RowDefinition Height="32" />
                                                             <RowDefinition Height="32" />
                                                             <RowDefinition Height="32" />
                                                          </Grid.RowDefinitions>

                                                          <TextBlock Text="Serial number:" Grid.Row="0" Grid.Column="0" Margin="8,8,0,0" />
                                                          <TextBox Text="{Binding [SER2]}" Grid.Row="0" Grid.Column="1" MinWidth="115" MaxWidth="115" HorizontalAlignment="Left" IsEnabled="False" />
                                                          <TextBlock Text="Item number:" Grid.Row="1" Grid.Column="0" Margin="8,8,0,0" />
                                                          <TextBox Text="{Binding [ITNO]}" Grid.Row="1" Grid.Column="1" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" IsEnabled="False" />
                                                          <TextBlock Text="To location:" Grid.Row="2" Grid.Column="0" Margin="8,8,0,0" />
                                                          <TextBox Name="RemoveLocation" Text="" Grid.Row="2" Grid.Column="1" MinWidth="115" MaxWidth="80" HorizontalAlignment="Left" />
                                                          <TextBlock Text="Warehouse:" Grid.Row="3" Grid.Column="0" Margin="8,8,0,0" />
                                                          <TextBox Name="RemoveWhs" Text="100" Grid.Row="3" Grid.Column="1" MinWidth="40" MaxWidth="40" HorizontalAlignment="Left" />

                                                          <Button Name="Install" Content="Remove" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left" Margin="0,0,50,0">
                                                             <Button.CommandParameter>
                                                                <mashup:Events>
                                                                   <mashup:Event SourceEventName="Click" TargetName="RemoveInstall" TargetEventName="Update" Debug="True">
                                                                      <mashup:Parameter TargetKey="RITP" Value="R" />
                                                                      <mashup:Parameter TargetKey="RESP" Value="202231" />
                                                                      <mashup:Parameter TargetKey="TRDT" Value="20130927" />
                                                                      <mashup:Parameter TargetKey="TRTM" Value="090909" />
                                                                      <mashup:Parameter TargetKey="WHLO" Value="{Binding Path=Text, ElementName=RemoveWhs}" />
                                                                      <mashup:Parameter TargetKey="RSC4" Value="CHG" />
                                                                      <mashup:Parameter TargetKey="ITNR" Value="{Binding [ITNO]}" />
                                                                      <mashup:Parameter TargetKey="BANR" Value="{Binding [SER2]}" />
                                                                      <mashup:Parameter TargetKey="TWSL" Value="{Binding Path=Text, ElementName=RemoveLocation}" />
                                                                      <mashup:Parameter TargetKey="NHAR" Value="{Binding [MTRL]}" />
                                                                      <mashup:Parameter TargetKey="NHSR" Value="{Binding [SERN]}" />
                                                                      <mashup:Parameter TargetKey="CFGR" Value="{Binding [CFGL]}" />
                                                                   </mashup:Event>
                                                                </mashup:Events>
                                                             </Button.CommandParameter>
                                                          </Button>
                                                       </Grid>
                                                    </GroupBox>
                                                 </StackPanel>
                                              </Grid>
                                           </Border>
                                        </Popup>
                                     </StackPanel>
                                  </DataTemplate>
                               </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                         </GridView.Columns>
                      </GridView>
                   </ListView.View>
                </ListView>
             </m3:MIListPanel>

             <m3:MIPanel Name="RemoveInstall">
                <m3:MIPanel.Events>
                   <mashup:Events>
                      <mashup:Event SourceName="RemoveInstall" TargetName="MOS256List" SourceEventName="UpdateComplete" TargetEventName="Refresh" />
                   </mashup:Events>
                </m3:MIPanel.Events>

                <m3:MIPanel.DataSource>
                   <m3:MIDataSource Program="MOS125MI" Transaction="RemoveInstall" InputFields="RITP,RESP,TRDT,TRTM,WHLO,RSC4,ITNR,BANR,TWSL,NHAR,NHSR,CFGR" />
                </m3:MIPanel.DataSource>
             </m3:MIPanel>

    </StackPanel>
    </TabItem>

 

GridView-Example4

The source code of the sample:

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

       <m3:MIListPanel Name="CRS620MIList">
       <m3:MIListPanel.Events>
          <mashup:Events>
             <mashup:Event SourceEventName="Startup" />
          </mashup:Events>
       </m3:MIListPanel.Events>

       <m3:MIListPanel.DataSource>
          <m3:MIDataSource Program="CRS620MI" Transaction="LstSuppliers" Type="List" OutputFields="SUNO,SUNM,PHNO,CUCD,BUYE" MaxReturnedRecords="4" />
       </m3:MIListPanel.DataSource>

       <ListView ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
          <ListView.View>
             <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
                <GridView.Columns>
                   <GridViewColumn Header="Supplier:" DisplayMemberBinding="{Binding [SUNO]}" />

                   <GridViewColumn Header="Supplier Name:">
                      <GridViewColumn.CellTemplate>
                         <DataTemplate>
                            <TextBox Name="Name" Text="{Binding [SUNM]}" />
                         </DataTemplate>
                      </GridViewColumn.CellTemplate>
                   </GridViewColumn>

                   <GridViewColumn Header="Phone:">
                      <GridViewColumn.CellTemplate>
                         <DataTemplate>
                            <TextBox Name="Phone" Text="{Binding [PHNO]}" />
                         </DataTemplate>
                      </GridViewColumn.CellTemplate>
                   </GridViewColumn>

                   <GridViewColumn Header="Currency:">
                      <GridViewColumn.CellTemplate>
                         <DataTemplate>
                            <TextBox Name="Currency" Text="{Binding [CUCD]}" />
                         </DataTemplate>
                      </GridViewColumn.CellTemplate>
                   </GridViewColumn>

                      <GridViewColumn Header="Buyer:">
                      <GridViewColumn.CellTemplate>
                         <DataTemplate>
                            <TextBox Name="Buyer" Text="{Binding [BUYE]}" />
                         </DataTemplate>
                      </GridViewColumn.CellTemplate>
                   </GridViewColumn>

                   <GridViewColumn>
                      <GridViewColumn.CellTemplate>
                         <DataTemplate>
                            <Button Content="Update">
                               <Button.CommandParameter>
                                  <mashup:Events>
                                     <mashup:Event SourceEventName="Click" TargetName="CRS620Update" TargetEventName="Update">
                                        <mashup:Parameter TargetKey="SUNO" Value="{Binding [SUNO]}" />
                                        <mashup:Parameter TargetKey="SUNM" Value="{Binding [SUNM]}" />
                                        <mashup:Parameter TargetKey="PHNO" Value="{Binding [PHNO]}" />
                                        <mashup:Parameter TargetKey="CUCD" Value="{Binding [CUCD]}" />
                                        <mashup:Parameter TargetKey="BUYE" Value="{Binding [BUYE]}" />
                                     </mashup:Event>
                                  </mashup:Events>
                               </Button.CommandParameter>
                            </Button>
                         </DataTemplate>
                      </GridViewColumn.CellTemplate>
                   </GridViewColumn>
                </GridView.Columns>
             </GridView>
          </ListView.View>
       </ListView>

    </m3:MIListPanel>
    <m3:MIPanel Name="CRS620Update">
       <m3:MIPanel.DataSource>
          <m3:MIDataSource Program="CRS620MI" Transaction="UpdSupplier" Type="Update" InputFields="SUNO,SUNM,PHNO,CUCD,BUYE" MandatoryInputFields="SUNO" />
       </m3:MIPanel.DataSource>
    </m3:MIPanel>

    <ui:StatusBar Name="StatusBar" Grid.Row="1" Grid.Column="0" />
 </Grid>

Regards
Ken Eric

Mashup – Browsing with F4 through a popup

Last week Thibaud invited me to share some of our M3 ideas from a customer’s point of view.
The invitation was accepted, hoping to make the community grow beyond just Infor.
I will be sharing some of our knowledge and experience on the subject mashup, and this is my first post.

One of the first thing the end-users requested after releasing our first mashups was the F4/browse functionality missing.
A few request for help was sent, but the main feedback was that this is not possible from a mashup and had to be part of a SDK application.
Unfortunately this was out of my range and a work around had to be made.
After spending quite some time googling/reading I came across the popup class.
“A Popup control displays content in a separate window relative to an element or point on the screen. ”

This is a simple example using the F4 command to open the popup and then allowing you to browse and write back with CurrentItemChanged.

Before:
F4

After:
F4Browse

Real world example, but this time with a button controlling the popup.

ExampleBrowse

And here is the 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.ColumnDefinitions>
		<ColumnDefinition Width="400" />
		<ColumnDefinition Width="*" />
	</Grid.ColumnDefinitions>
	<Grid.RowDefinitions>
		<RowDefinition Height="40" />
		<RowDefinition Height="Auto" />
	</Grid.RowDefinitions>

	<StackPanel Grid.Row="0" Margin="8,8,0,0" Orientation="Horizontal">
			<StackPanel.InputBindings>
        		 <KeyBinding Key="F4" Command="mashup:MashupInstance.MashupCommand">
					 <KeyBinding.CommandParameter>
						<mashup:Events>
							<mashup:Event Target="{mashup:SetProperty ElementName=BrowseLocation, Path=IsOpen}">
								<mashup:Parameter TargetKey="Value" Value="True" />
							</mashup:Event> 	
						</mashup:Events>
					</KeyBinding.CommandParameter>
				</KeyBinding>
      	</StackPanel.InputBindings>

			<TextBlock Text="Location:" />
			<TextBox Name="Location" Width="50" Height="20" Margin="5,0,0,0" />	

	</StackPanel>

	<StackPanel HorizontalAlignment="Left" Grid.Column="0" Grid.Row="0">

		<Popup Name="BrowseLocation" Width="600" Height="450" Popup.StaysOpen="False">
			<Border Background="White">
				<Grid>
					<Grid.RowDefinitions>
						<RowDefinition Height="400" />
						<RowDefinition Height="50" />
					</Grid.RowDefinitions>
					<Grid.ColumnDefinitions>
						<ColumnDefinition Width="600" />

					</Grid.ColumnDefinitions>
					<m3:ListPanel Name="ListLocation" Grid.Column="0" Grid.Row="0" EnableBasicOptions="False" IsDefaultActionEnabled="False" EnableRelatedOptions="False">
						<m3:ListPanel.Events>
							<mashup:Events>
								<mashup:Event SourceEventName="Startup">
									<mashup:Parameter TargetKey="MLCONO" />
									<mashup:Parameter TargetKey="MLFACI" DefaultValue="100" />
									<mashup:Parameter TargetKey="MLWHSL" />
								</mashup:Event>

								<mashup:Event SourceName="ListLocation" SourceEventName="CurrentItemChanged" Target="{mashup:SetProperty ElementName=Location, Path=Text}">
										<mashup:Parameter TargetKey="Value" SourceKey="WHSL" />
								</mashup:Event>
							</mashup:Events>
						</m3:ListPanel.Events>
						<m3:ListPanel.Bookmark>
							<m3:Bookmark Program="MMS010" Table="MITPCE" KeyNames="MSCONO,MSWHLO,MSWHSL" SortingOrder="1" />
						</m3:ListPanel.Bookmark>
					</m3:ListPanel>

					<Button Name="Close" Content="Close" Grid.Row="1" Grid.Column="0">
								<Button.CommandParameter>
									<mashup:Events>
										<mashup:Event Target="{mashup:SetProperty ElementName=BrowseLocation, Path=IsOpen}" SourceEventName="Click">
											<mashup:Parameter TargetKey="Value" Value="False" />
										</mashup:Event>
									</mashup:Events>
								</Button.CommandParameter>
					</Button>	
				</Grid>
			</Border>
		</Popup>
	</StackPanel>
</Grid>

Regards
Ken Eric

Event graphs for Mashups

Today I introduce a new home-made tool that automatically generates event graphs from a Mashup‘s source code.

Motivation

I am currently doing some maintenance on a monster Mashup that has 20 data controls choreographed by 27 events where the height of the event tree is greater than 3, and I needed to understand the sequence of events so I can implement several new requirements in the Mashup without breaking the entire Mashup.

The tool

To assist me, I implemented a home-made tool with XSLT and XPath that automatically transforms the <mashup:Event> nodes of the Mashup XAML source code into a directed graph in the DOT graph description language that I rendered in GraphViz, an open source graph visualization software. I used what I learned from two of my previous tools: dependency graphs for data conversion, and Web Service pretty print.

Suppose we have a Mashup with a Search button that triggers a search on a Customer list. We would have the following XAML code:

<mashup:Event
    SourceName="BtnSearch"
    SourceEventName="Click"
    TargetName="CustomerList"
    TargetEventName="Search" />

The idea is to take each event’s properties SourceName, SourceEventName, TargetName, and TargetEventName, and display them in a directed graph with nodes, edges, and labels using this DOT syntax:

digraph g {
    BtnSearch -> CustomerList [label="Click > Search"];
}

The result will look like:

2
We can automatically transform the XAML code into that DOT code with the following XSLT code:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI">
    <xsl:template match="/">
        digraph g {
            <xsl:apply-templates select="//mashup:Event"/>
        }
    </xsl:template>
    <xsl:template match="mashup:Event">
        <xsl:value-of select="@SourceName"/> -> <xsl:value-of select="@TargetName"/> [label="<xsl:value-of select="@SourceEventName"/> > <xsl:value-of select="@TargetEventName"/>"];
    </xsl:template>
</xsl:stylesheet>

The problem is that not all Events are fully qualified with all the properties SourceName, SourceEventName, TargetName, and TargetEventName. For instance the Mashup has an implicit SourceName <Global> that does not need to be explicitly qualified in the code. And the Button has the implicit SourceEventName “Click” that does not need to be explicitly qualified either. Thus, we need to handle those cases in the XSLT code. The resulting XSLT code is long and complicated with many if-then-else to test if the properties are blank, and, if they are, to test if the control has a known implicit property.

Finally, we will need an XSLT processing engine in order to get the result. Most major browsers have a built-in XSLT engine, for instance Microsoft Internet Explorer, Google Chrome, Safari, and Mozilla Firefox have a built-in XSLT engine. To test my tool on your computer, you can use Internet Explorer, Safari, and Opera as they will process the XSLT file locally from the disk with file://… On the other hand, Firefox and Chrome for security reasons will only process the file if it’s served from a web server with http:// so you would have to setup your localhost.

You can download the final XSLT file at http://thibaudlopez.net/Mashups/EventGraph.xslt

Preparation

Before using my tool, follow these steps:

  1. Download Graphviz from http://www.graphviz.org/ and start it from Windows > Start > Graphviz > gvedit.exe.
  2. Download my XSLT file from http://thibaudlopez.net/Mashups/EventGraph.xslt and save it somewhere in your file system.

How to use

To use my tool, follow these steps:

  1. Get some Mashup XAML code, for example from the Mashup Designer built-in examples, and save the XAML in the same folder as the XSLT file you saved previously:4
  2. Rename the file extension from XAML to XML so we can open it in one of the browsers later:
    5
  3. Add the following XSLT processing instruction at the top of the XML file:
    <?xml-stylesheet type=”text/xsl” href=”EventGraph.xslt”?>
    6
  4. Open the file in one of the browsers, for instance Internet Explorer:
    7
  5. In Graphviz, select File > New.
  6. Copy/paste the code that was generated in the browser:
    10
  7. Select Graph > Layout (F5) to generate the graph:
    11
  8. That’s it!

Results

Here are the resulting event graphs for five of the Mashup Designer’s built-in examples:

  1. REST Lists:
    213
  2. Item list & details:
    1 3
  3. Customer Addresses & Map:
    23
  4. Item list & visualizers:
    1 2
  5. List & edit Customers:
    1 10

Future work

In a future work, the XSLT code would have to be refined to cover all possible scenarios (blanks and implicit properties).

Also, we could include the Bookmark’s Keys or the Event’s Parameter Keys in the event graph, for example CONO, CUNO, ADRT, ADID.

7

Data conversion techniques

Here below is an old slide I found in my archives where I list my known techniques for data conversion, i.e. how to push data into Infor M3, also known as data entry. This list intends to remind readers there are more solutions than the traditional techniques.

Data conversionTechniques

Traditional entry points

The two traditional entry points are:

  1. API – The traditional entry point is to call M3 API. Advantages: it’s the fastest and most reliable technique, and the most widespread in terms of platforms supported, libraries, tools, and documentation. Disadvantages: there aren’t M3 API available for every program/field/operation in M3, as given by the M3 API Repository – MRS001.
  2. MDP – When there’s no M3 API available, we use the other traditional entry point, Lawson Web Services (LWS) of type M3 Display Program (MDP) to simulate a user going through the screens at the middleware level in M3 Net Extension (MNE). Advantages: with the Lawson Web Services Designer we can create the equivalent of an M3 API, for most M3 Programs, in almost no time. Disadvantage: it’s less efficient to run than M3 API as there are more layers to traverse.

Those are the traditional techniques. And we massively call them with for example M3 Data Import (MDI), Smart Data Tool (SDT), M3 E-Collaborator (MeC), Visual Basic macros in Microsoft Excel, ProcessFlow Integrator (PFI), Infor Process Automation (IPA), Tibco, WebMethods, or custom Java/C#/VB programs, with the data coming from a source like for example a Microsoft Excel spreadsheet, a CSV or plain text file, or a staging database.

Alternate techniques

If the traditional entry points fail, there are two alternate techniques.

  1. Manual entry – We can always do manual data entry. Advantage: it requires almost no skills, no programming, and no tools. Disadvantage: it can become humanly impossible to manually enter large amounts of data.
  2. MAK – Alternatively, we can write an M3 modification with MAK, to create a new API or modify an existing one. Advantages: it’s the ultimate solution. Disadvantages: it requires an MAK developer, it can take time, and M3 mods create a maintenance problem.

Despair techniques

Then, there are the following techniques which are less know and which I use when I’m at a loss of ideas:

  1. MForms Automation – When there are no M3 API available, and when Lawson Web Services of type MDP fail for rare M3 programs, we can try to reproduce the steps with MForms Automation and write a Smart Office Script that loops thru a data source and executes the MForms Automation at each iteration. This is a proven technique and Seth will soon write a post illustrating this solution. Advantage: It’s the last card on the deck when you lost hope. Disadvantage: It’s less efficient because it’s at the user interface level.
  2. Bookmarks – Similarly, we can write a Smart Office Script to execute Bookmarks in a loop of the form mforms://bookmark?program=CRS620&tablename=CIDMAS&keys=IDCONO…
  3. MNEAI – Likewise, we can inject a piece of JavaScript in M3 Workplace to simulate a user’s data entry, and loop through a data source we get with JavaScript.
  4. H5 Client – We can do the same JavaScript injection for H5 Client.
  5. Macro – We can record the mouse movement and click events, and the keyboard keystrokes, and use a Windows program to replay them. Advantages: It’s the last solution available out of desperation. Disadvantage: it will break at the slightest change in window position or popup, and it will be slow.

Forbidden techniques

Finally, as a reminder, we never use SQL INSERT/UPDATE/DELETE to M3, as that would break the integrity of the ERP, it would bypass the cache of the data abstraction layer, and it would void warranty for support.

That’s it! Thanks for reading. Subscribe below.

Using Dynamic WS to consume a LWS in a script

Here is a new solution to call SOAP Web Services from a Smart Office script that complements the previous known solutions. It’s a very easy and fast way to call LWS and does not require you to write any C# or XML.

It’s using a private API in Smart Office so it might change in future releases, without any announcement.

Continue reading Using Dynamic WS to consume a LWS in a script