You don’t have to be a developer to create Mashups. A business user can do great Mashups. With Mashups you have the full power of WPF and the simple use of our Mashup Controls. Events play an important role when it comes to passing data. Recently I have seem more than one example of incorrect use of curly braces. Today I’ll try and explain the difference between a binding, markup extension methods that we have created and our variable substitution using curly braces. This is advanced stuff so you need to be interested in the more advanced technical stuff.
Data bindings
Data binding is the process that establishes a connection between the application UI and business logic. If the binding has the correct settings and the data provides the proper notifications, then, when the data changes its value, the elements that are bound to the data reflect changes automatically.
This is when you bind a value from one source or control to another. The syntax looks like this:
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c="clr-namespace:SDKSample"> <DockPanel.Resources> <c:MyData x:Key="myDataSource"/> </DockPanel.Resources> <DockPanel.DataContext> <Binding Source="{StaticResource myDataSource}"/> </DockPanel.DataContext> <Button Background="{Binding Path=ColorName}" Width="150" Height="30">I am bound to be RED!</Button> </DockPanel>
A binding can have different sources. The most common is that there is a DataSource object attached to the DataContext of the control. The DataContext is found on the FrameworkElement which is one of the base classes so all UI elements have this property.
The Mashup controls uses this and set data objects to the DataContext of the control, or it sets itself as the data object that has properties or perhaps and indexer [NAME], that can read properties via the name. A data object is not a specific type of object. It is just a class. It can be a DataSourceProvider, but it doesn’t have to be.
The DataContext is propagated. In the code example above the Button does not have the DataContext set so it checks the parent’s DataContext. In this case the DockPanel has the DataContext set and that object has ColorName property. If you write a binding and you don’t see anything the most common mistakes are:
1. The Path, the property name is not correct. There is no such property in the DataContext object.
2. There is no DataContext object.
3. In the case of a Binding to another element the ElementName is incorrect.
4. There is a missmatch of types. You think the property is a list of things but it is something else like a string.
If you have a M3List there is a CurrentItem property that you can use to get a value from the selected row in the list or for the selected record in a DetailPanel. In that case you use a Binding but set the Binding Source to the M3List or whatever control that has the Property you want to bind to.
In the example below I have a M3 List and then I display some values from the selected row in the list.
The binding that does the trick looks like this:
<TextBlock Text="{Binding ElementName=customerList,Path=CurrentItem[CUNM]}" />
Note the ElementName which is customerList. This is the Name of the M3 list. The M3List has a CurrentItem property which returns an object that has an index. Indexes are always accessed with brackets.
Here is the full Mashup:
<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="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <m3:ListPanel Name="customerList"> <m3:ListPanel.Events> <mashup:Events> <mashup:Event SourceEventName="Startup" TargetEventName="List"> <mashup:Parameter TargetKey="OKCONO" /> <mashup:Parameter TargetKey="OKCUNO" /> </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> <StackPanel Margin="20" Grid.Row="1"><Label Content="Values with bindings from list: " /> <Label Content="CUNO" /> <TextBlock Text="{Binding ElementName=customerList,Path=CurrentItem[CUNO]}" /> <Label Content="CUNM" /> <TextBlock Text="{Binding ElementName=customerList,Path=CurrentItem[CUNM]}" /></StackPanel> </Grid>
For more information about bindings please read MSDN.
Markup extensions
Markup extensions are a general feature of the XAML language. The most common markup extensions used in WPF programming are those that support resource references (StaticResource and DynamicResource), and those that support data binding (Binding). So when you are using a Binding you are using a Markup extension. A markup extension starts- and ends with a curly braces.
As part of Mashups and Lawson Smart Office we have created a few Markup Extension methods.
For example:
// Getting a profile value <mashup:DataParameter Key="WS.Wsdl" Value="{mashup:ProfileValue Path=M3/WebService/url}" /> // Getting a language constant from a languagefile within the mashup project <TextBlock Text="{mashup:Constant Test1}"/> // Getting language from M3 <Label Content="{m3:Constant Key=OI05612,File=MVXCON}" /> //Extension for setting any property on the target element object with the specified name. // <mashup:Event SourceEventName="Click" Target="{mashup:SetProperty ElementName=MyTextBox, Path=Text}"> //Markup extension for accessing string values from the user context. //<TextBlock Text="{mashup:UserContextValue Path=M3/CurrentCompany}" />
Read more on Markup extensions on MSDN.
Variable substitution
Variable substitution is something that we support within the Event framework. You can chain events and their values so that you can use a value from one event and give it a name and then use it as a replacement variable. Some of the other controls might also support this behavior on different properties.
<mashup:DataParameter Key="REST.BaseAddress" Value="http://ws.spotify.com/lookup/1/?extras=albumdetail&uri={AlbumUri}" />
In the example above (which is the DataService REST example) the AlbumUri will be replaced by the value of AlbumUri. The Album Uri can come from two places:
1. An Event Parameter
2. From the DataPanel – it is a value that the mashup control can resolve
3. A combination of both 1 and 2
In this case the AlbumUri is a replacement variable and the value is passed in the Event. But the value in the event is itself a replacement variable {@href} which means that the framework will ask the Mashup control, in this case DataListPanel for the value of “@href”.
<mashup:DataListPanel Name="PanelAlbums" Margin="8" Grid.Row="3" Grid.Column="0"> <mashup:DataListPanel.DataService> <mashup:DataService Type="REST"> <mashup:DataService.Operations> <mashup:DataOperation Name="List"> <!-- Note! Replacement variable AlbumUri--> <mashup:DataParameter Key="REST.BaseAddress" Value="http://ws.spotify.com/lookup/1/?extras=albumdetail&uri={AlbumUri}" /> <mashup:DataParameter Key="REST.RemoveNamespace" Value="True" /> <mashup:DataParameter Key="REST.XPath" Value="artist/albums/album" /> </mashup:DataOperation> </mashup:DataService.Operations> </mashup:DataService> </mashup:DataListPanel.DataService> <mashup:DataListPanel.Events> <mashup:Events> <mashup:Event SourceName="PanelArtists" SourceEventName="CurrentItemChanged" TargetEventName="List"> <!-- Note! AlbumUri is passed in the event. The value looks like a binding not it isn't!--> <!-- {@href} would not be valid since it is not a Markup Extension and all markup extensions are surounded with {markupextension}. {} is used to escape--> <mashup:Parameter TargetKey="AlbumUri" Value="{}{@href}" /> </mashup:Event> </mashup:Events> </mashup:DataListPanel.Events> <ListView Name="ListAlbums" ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}"> <!-- ListView content here ---> </mashup:DataListPanel>
The event parameter that has the Value set to “{}{@href}” is very interesting. Setting the value to {@href} directly will result in: “Character ‘@’ was unexpected in string ‘@href’. Invalid XAML type name.” but a more common error if we did not have the @-sign would be:
Cannot create unknown type ‘{http://schemas.microsoft.com/winfx/2006/xaml/presentation}href’.
or if we have a value that was set to something like this “{href}/list/albums we would get:
Unexpected token after end of markup extension
Why? Because the value starts with “{“, it is processed as a markup extension. In order to tell WPF that it is not a markupextension we must escape it by adding {} giving us {}{@href}.
An example from the real world
We have covered the different use and meaning of {}. Now let’s look at an example to see if you can spot what is wrong. The scenario is the following.
In a Mashup that calls Lawson Web Service, how can you make the URL dynamic depending on the profile we’re currently using (DEV, EDU, PRD, TST, etc.)? Right now the value is hard-coded by setting the value to the control like this:
<mashup:DataParameter Key="WS.Wsdl" Value="https://server/LWS/svc/Customer.wsdl" />
Instead, we want to use the value of the Profile Editor and then add on /svc/Customer.wsdl
I have tried this, but it does not work:
<mashup:DataListPanel.DataService> <mashup:DataService Type="WS"> <mashup:DataService.Operations> <mashup:DataOperation Name="Get"> <mashup:DataParameter Key="WS.Wsdl" Value="{}{mashup:ProfileValue Path=M3/WebService/url}/svc/Customer.wsdl" /> <mashup:DataParameter Key="WS.Address" Value="{}{mashup:ProfileValue Path=M3/WebService/url}/services/Customer" /> <mashup:DataParameter Key="WS.Operation" Value="getForecast" /> <mashup:DataParameter Key="WS.Contract" Value="CRF23" /> <mashup:DataParameter Key="mws.user" Value="LSO.USER" /> <mashup:DataParameter Key="mws.password" Value="LSO.PASSWORD" /> <mashup:DataParameter Key="getForecast1.Company" /> <mashup:DataParameter Key="getForecast1.Warehouse"/> <mashup:DataParameter Key="getForecast1.Item" /> </mashup:DataOperation> </mashup:DataService.Operations> </mashup:DataService> </mashup:DataListPanel.DataService>
Can you spot what is wrong?
They are using mashup:ProfileValue which is a markupextension, so it cannot be escaped nor does it support any kind of concatenation. If you use a markup extension you cannot add stuff after. You need to do this in two steps.
1. Get the value from the profile
2. Use our own LSO variable substitution.
Not all elements supports variable substitution. I think we did add support for DataParametes in the DataListPanel and I know we did add support for setting DataParameters in events. So if the operation that the DataListPanel has is List you would have a List event to trigger it. In the event you can set WS.Wsdl.
Like this:
<Button Content="List" IsDefault="True" Style="{DynamicResource styleButtonPrimaryMashup}"> <Button.CommandParameter> <mashup:Events> <mashup:Event TargetName="listControl" SourceEventName="Click" TargetEventName="List"> <mashup:Parameter TargetKey="WS.Wsdl" Value="http://api.search.live.net/search.wsdl" /> </mashup:Event> </mashup:Events> </Button.CommandParameter> </Button>
If you would like to extract the base part of the Uri this is the next step:
Don’t forget to turn un debug in the Advanced section on the Events tab.
Using the events will work in more scenarios so that is what I’ll show you.
First step is to take the base part and define it as a Parameter called BaseUri. Then let the WS.Wsdl parameter use the substitution variable BaseUri.
<mashup:Event TargetName="listControl" SourceEventName="Click" TargetEventName="List"> <mashup:Parameter TargetKey="BaseUri" SourceKey="BaseUri" Value="http://api.search.live.net" /> <mashup:Parameter TargetKey="WS.Wsdl" Value="{}{BaseUri}/search.wsdl" /> </mashup:Event>
Next step is to replace the hardcoded BaseUri value with a profile extension.
<mashup:Event TargetName="listControl" SourceEventName="Click" TargetEventName="List"> <mashup:Parameter TargetKey="BaseUri" SourceKey="BaseUri" Value="{mashup:ProfileValue Path=M3/WebService/url}" /> <!-- Syntax for finding a setting is group/application/property--> <mashup:Parameter TargetKey="WS.Wsdl" Value="{}{BaseUri}/search.wsdl" /> </mashup:Event>
Works like a charm!
Karin – Nice examples for this – particularly when you have a mashup that combines multiple list that may depend on changing values in each one (e.g MMS001/MMS002/MMS003 /MMS060/PDS001) – those combinations are a real headache to try and syncronise. Cheers, Paul
Thanks,
Bindings combined with variable substitution is a powerful tool!
Hello Karin,
Can you refresh a MIComboBox datasource after it has been initialized. First off I do not want the combobox cacheable. I would like to create a Style that trigger a data source refresh when the combobox is clicked. I believe that I have to use an UpdateSourceTrigger property change… here is what the combobox XAML looks like:
Hi,
You can have the combobox not to cache by settings IsCacheable=”False” on the MIDataSource.
Please escape your code in comments with the code or sourcecode tag, see http://en.support.wordpress.com/code/posting-source-code/.
I would like to see your XAML and the style so that I can think about if there is a way to get your scenario to work. Is this a new entry scenario only? Please provide more info.
You can re-trigger with events but the force the source to update via bindings I don’t think our control supports it. But we might add it or there might be a work-around.
Hello Karin,
Please see the following link for the published code.
http://wp.me/p4ra5v-3
Regards,
Eric
Maybe this one is better.
http://ericwayker.wordpress.com/2014/03/14/infor-mashup-micombobox-refresh-datasource/
Hi Eric,
Thank you for the XAML. Sorry for the late reply. We are working hard on the next version of Smart Office. I did dig into the MICombobox source and you can’t trigger it like that. It actually sets the ItemsSource directly and does not support binding. There is no way to trigger refresh with a binding – only Mashup Events.
Thank you.
Pingback: How to get the URL to Lawson Web Services in a Mashup « M3 ideas
Hi, do you know if it’s possible to enter a list of values in the value field for the target keys? I’m trying to make a tab in a mashup that will show partly delivered and fully delivered order lines. In this case I need order lines which are in status 36 or 46 or 66 or 67 or 69. At the moment it works when I enter status 66 to 69 (= range) but I need a list functionality for this.
When I enter 36,66 this results in returning also roder lines in status 44 for example so it sees this as a range instead of a list. Any possibility to solve this with brackets, , or special code ?
Thank you, Elly
Hi Elly,
It is not possible to set ranges. I’m not sure what you mean with “when I enter status 66 to 69” it works. Are you talking about a key to a bookmark or an event key? Filter?
Please explain in more detail.
Pingback: Mashups, WebServices and Variable Substitution | Potato IT
Karin – Great Stuff. I was wondering if you can use data binding from a list panel to pass to a button while using MForms automation. My requirements list data from DRS005 (DROUTE) where I would use attribute DRSDES to pass to a button, which then uses MForms automation
to open panel DRS011. The automation for DRS011 would open with parameters for Place of Loading and Priority. I was hoping that I could use the data binding to pass to an MForms automation. I have attempted to create a TargetKey event in the Button which I was hoping would be read in the LinkUri as a dynamic resource. I doesn’t look like users post code here but I am willing to post if you would like.
Hi Eric
You need to escape code using the code keyword enclosed with hard-brackets (I think they are called).
Like this but removing the first bracket and the last one becuase I can’t seem to get this escaped correctly:
[[code]
your code here
[/code]]
I think that what you are asking for is possible as long as those variables you would like to add to the automation URL, does not brake the URL, which it would if it contains special chars or spaces. But on the other hand my recommendation is to use replacement variables in the event on the button.
So you define variables that you would like to pass in the automation URL, such as DRSDES. Where that vailable goes in the automation URL you but {DRSDES} instead. Then you add a parameter to the event and call it DRSDES and the value should be set by a Binding that points to the listing from DRS005.
You need to use varaible substitution as well as Bindings.
Your result would look something like this:
LinkUri should support variable substitution in the event. But I can’t test this right now or do a better example because I’m on vacation with no access to my computer at the office.
You can bind to a value on the panel (from a certain version anyhow). Check the API documentation for the propertyname (available from the Help menu in the Designer), which I think is CurrentItem.
Let me know if you still have issues.
Hello Karinpb
I am struggling with the above. I am picking up the value from the list panel when I press the button, that works brilliantly, but it wont add the details the the A panel it opens? Any ideas?
Many thanks in advance.
Damian
Hi, The example in the comment is very simplified. The link is not a correct automation link. You actually need to have a specific tool to be able to build an automation link. It’s basically an XML document that you send as a parameter. Today I would try to see if the A panel could be opened by a bookmark instead. First try with a hardcoded link – if that does not work then the link you are using is not correct. For bookmarks there is a test program in M3 that you can use MTS043.
Hello.
I am currently learning mashups and i am curious if anyone can explain the logic behind the parameters in the event tab. I am having difficulty connecting, “to me”, two very basic programs. MWS410 to MWS420. ie click on a line in MWS410 and any avilable picking lists show in MWS420.
Without anything other than the event, ie source, source event, target etc… the delivery number populates in MWS420 when changing item. however the warehouse code does not. Now ive tried linking WHLO to WWWHLO or setting a default value but nothing.
This seems to be my stumbling block with most things. So as requested, if people can talk in ‘stupid’ terms and explain to me the logic with a few examples i would greatly appreciate it, and maybe i wont of pulled my hair out in the next few weeks.
Thanks in advance,
Daymo Clark
Hi, I’m sorry for the late reply but I received this question during vacation. When there are issues with connecting events there are often an issue with the value not being available on the first panel or that the name of the field is different on the panel that wants to receive the value. Setting a default value is therefor a very good first test. Since you have tried a default value the next step is to verify the name of the field in MWS420. Have you tried the input for MWS in the test program for MTS043? This program is a test program for bookmarks and if the parameters you pass in with the Mashup event does not work here you are missing some required parameter.
The general approach for finding out what to pass to a program is the following:
1. Investigate the fields that needs input in the receiving program (by turning on help and reading the field names for example).
2. Check if all fields are available in the list program (it’s often a list)
3. Add the event and turn on debug to see that all fields has values.
4. If you see all the values but it still does not work test in MTS043
It’s possible that a program does not have bookmark support.
Hello Karinpb,
Thanks for this. Very very helpful.
In regards to populating using fields in a source field and targetting a W1OBKV field, how does this work?
Thanks
Damian
Hi Damian,
I’m not sure I understand your question. You would like to set a filter field W1OBKV from another mashup control? It should work with the full target name W1OBKV and the source field can be short or long. The logic is to look for the field using just the short name to start will, but a full name will find the field directly. I think those position fields should work in the same way as other fields.
Hi Karinpb
Thanks again, you answered my question perfectly.
Last issue (for now 🙂 ), How do i set a filter in, for e.g. OIS300. where it will only show Order Type value C10? Or a specific range, like A1 to A2 etc.
Thanks again you are proving to bea life saver.
Kind Regards
Damian
How do you reset the combobox to selected value back to blank?
Given
I’ve tried resetting the value via Path=SelectedValue and also Path=Value via a button event. Both didn’t work.
Is this possible?
Hi,
How are you adding the possible values to the combobox? To be able to get it back to blank you must have a value that is blank within the options available – but there might be a work-around. What is the scenario?
Select from a combobox with for example “item group” from an API but in some cases you want to add it as blank? I think we added an option to insert an empty result row simply for this scenario. The MIComboBox has a property EnableEmptyValue that you can set to true that will insert an empty value in the data and then your can reset the value. It was included in: Smart Office 10.1.2 Core HF2 build 29 . If you are using a standard Combobox then you must have an empty value in the itemssource or in the possible values.
Hi,
How do I bind a result of a REST service to a detail panel?
I had a look on the Spotify test mashup and tested a bit but I don´t get it to work.
I have a REST service that delivers just one line and I want to show this in a detail panel format.
I can bind it to a list view but not to detail panel.
Can you maybe do an example on the Spotify mashup?
Thank you in advance!
Hi.
I’m afraid we are close to a deadline and I will not be able to do an example. In most cases the issue is with namespaces or the XPath. Try the Xpath in a standalone tool and make sure you strip out namespaces. If you can bind to a list your should set the root to the path of the list. I think the property is called RootPath or something. Please check the API documentation.
Pingback: MForms Automation in Mashups – M3 ideas
Hello Karin.
I have created a DataListPanel which is calling a RESTful service. The response is returned just fine and I am able to display the resulting data in a ListView. During a CurrentItemChanged event I would like to bind the value from the selected row and column to a variable which I will then use to create POST/PUT requests from a button object. Do you have any code snippets that might help?
Hi Eric,
I don’t have that many examples out of the box except for those we have on the blog. You would have two panels, possibly an XML template. It depends more on the data the master-detail is the same as in other examples. Attached is one for Landmark. With your XML you would use bindings for the parameter instead. I’ll see if I can find a better example. It’s tricky because I mostly do small test mashups. Perhaps another reader has better examples?
Hello again Karin,
Is there any way to display the HTTP response message from a REST-ful call in the mashup data panel? I usually get a successful HTTP-200 message back from the REST-ful call; however, there are instances where the response status code might be a 400 type error where the client has decided the values I’ve sent for processing are stale or maybe not valid. After the message fails all I get is a dialog saying there was an error. Maybe there is a data parameter I am missing. A perfect example would be if I set the wrong password on REST.password parameter; how do I see the response from the server? Thank you as always.
Is there any way to display a REST error response in a GridViewColumn where you can just ask the XPath. My initial REST.Xpath is consolidatedShipments/shipment. That wouldn’t work because the error comes back at the root and is in text/plain. Can you use some sort of dot dot notation to find the error message or a different binding usage?
Hi Eric,
There is no way to have the XPath set and then also get the error message. If there is an error message is the reply still an XML document? In that case you might be able to get something to work with a conditional even. But you would never get the error message in the GridViewColumn. You might be able to get it in a TextBox or label. If the root is different and you can add a condition to find the error node or something. But if it is just plain text in the body – you are out of luck. No trick will work because the REST data service only works will XML. But then you need to set the XPath yourself on the ItemsSource for the grid view since the DataContext of the DataPanel will always be the entire document. I’m afraid I don’t have an XML web service to try on but I’m thinking that it might work but it is definitely pushing the boundaries for what the DataPanels can do. Are you sure that you don’t get a HTTP error? I think there are room for improvements in that area.
Thank you Karin. I will make a few changes on the REST response. This sounds like I may have created my own problem then. I will let you know what happens next. Thank you as always.
HI Karin,
I have a mashup that calls a web service that executes an SQL. Result Collection are fine when testing in the datalist service configuration and LWS eclipse. Header also shows but rows don’t show. I’ve tried multiple binding syntax for the DisplayMemberBinding but nothing really shows. Also, I’ve come to a point where values are already hardcoded and list is being executed upon startup. When I change max result size to below the results being returned an error occurs meaning I am sure that there is a return from the webservice.
Can you show the data in tool://wstest?
HI Karin,
Here it is.
Hi Karin,
I have the same issue, have you please any update for this question ?
thank you
Hi Karin,
I have an MIList calling an API below, but I need to convert the N196 from -1,0,1 to “NA”,”No”,”Yes”. Is this possible?
Regards,
Jonathan
Hi, there is no such converter.
Pingback: Mashups, SOAP WebServices and SAML | Potato IT