Tuesday, 30 December 2008

InfoPath Rich Text Display in Form: Expression Box

Recently I faced an issue whereby a customer needed to pull rich text (XHTML) from a database, and have that displayed in the form (read-only) - through a web service.

For whatever reason, I couldn't use the Rich Text Box control within InfoPath to display the data. Normally I would just use an expression box to display read-only data on the form, as it renders and resizes appropriately and looks seamless.

However - the expression box was just rendering the XHTML source code ("<div class="'....'">asfsdgf</div>....."). So - to force the expression box to render the source code 'properly', we have to open the view xsl source file, and modify the tag that renders the data. This is easier than it sounds:

1. Bind an expression box to your Rich text data source element
2. File -> Save as Source Files
3. Open the appropriate view.xsl file in notepad
4. Find your expression box in the markup. This will look like <xsl:value-of select="MyElement" />
5. Add the following parameter to the xsl:value of tag: disable-output-escaping="yes"
So the updated tag will read:
<xsl:value-of select="MyElement" disable-output-escaping="yes" /> (where "MyElement" is your data source element).
6. Save, close, open the manifest file up in InfoPath and presto - your Rich Text XHTML is rendered as HTML in the form rather than as plain text.



This bugged me for a while - so hopefully it might save some of you some time!

davros.

Thursday, 4 December 2008

InfoPath and Great Plains Web Services: Update Customer Address Sample

This week I was asked to explore some the new web services available out the box with GP 10.0. It seems there are services to do pretty much anything you want with GP (Programmers Guide: https://mbs.microsoft.com/downloads/customer/WSProgrammersGuide.pdf). I thought I'd use some to create an InfoPath form to update customer details in GP. I had a dig around on the web, but didn't find any examples of InfoPath being used with these services, which seemed strange…


…until I found that alas – they are not InfoPath 'friendly'. Because of the way these services work it becomes necessary to create a middle tier web service ourselves, between the form and the GP web services.


[This posting is not a run-down of the web services in GP (see the above programmers guide for that). Instead it should serve as a starting point to show how we can use InfoPath to interact with GP data.]



Creating Our Web Service



  • Create a new Web Service project in Visual Studio
  • Add a Web Reference to the Dynamics GP Web Service. (Usually under /DynamicsGPWebServices/DynamicsGPService.asmx)



  • Now create our required Get and Set Web Methods (see code sample below)

Get Customer List:

[WebMethod]
public CustomerSummary[] GetCustomerList()
{
CustomerSummary[] custList;
CompanyKey companyKey;
Context context = new Context();
LikeRestrictionOfString classIdRestriction;
CustomerCriteria customerCriteria;


// Set up the Web Service
net.blackandblue.server01.DynamicsGP GPServ = new DynamicsGP();
GPServ.UseDefaultCredentials = true;

companyKey = new CompanyKey();
companyKey.Id = (-1);

context.OrganizationKey = (OrganizationKey)companyKey;
context.CultureName = "en-US";

classIdRestriction = new LikeRestrictionOfString();
classIdRestriction.EqualValue = "USA-ILMO-T1";

customerCriteria = new CustomerCriteria();
customerCriteria.ClassId = classIdRestriction;

// Get a list of customers matching the above restrictions
custList = GPServ.GetCustomerList(customerCriteria, context);


return custList;


}







Despite this method returning a custom array of customers, this renders through the web service as XML, and InfoPath is quite happy to pick up the fields. Below is the data set seen after connecting to my new web method in InfoPath (left).

This data populates a drop down list box in InfoPath. After selecting a customer and address, I want the user to be able to update the address and submit back to my web service – which in turn formats the data and calls the GP Web Service.



The method shown below either adds a new customer address, or updates an existing one:

[WebMethod]

public
bool UpdateAddress(string custID, string addressID, string line1, string line2, string line3, string city, string county,
string postcode, string contactPerson, string phone1Val, string phone1CCode, string phone1Ext, string phone2Val, string phone2CCode, string phone2Ext, string phone3Val, string phone3CCode, string phone3Ext, string AddUpdate)
{
CompanyKey companyKey;
Context context = new Context();
CustomerKey customerKey;

// Set up Web Service
net.blackandblue.server01.DynamicsGP GPServ = new DynamicsGP();
GPServ.Credentials = myCred;
GPServ.UseDefaultCredentials = true;

companyKey = new CompanyKey();
companyKey.Id = (-1);

context.OrganizationKey = (OrganizationKey)companyKey;
context.CultureName = "en-US";

// Assign Unique Keys - to define customer and address to update
customerKey = new CustomerKey();
customerKey.Id = custID;

CustomerAddressKey custAdressKey = new CustomerAddressKey();
custAdressKey.Id = addressID;

// Set customer address fields
CustomerAddress custAddress = new CustomerAddress();
custAddress.Key = custAdressKey;
custAddress.Key.CustomerKey = customerKey;

custAddress.Line1 = line1;
custAddress.Line2 = line2;
custAddress.Line3 = line3;
custAddress.City = city;
custAddress.State = county;
custAddress.PostalCode = postcode;
custAddress.ContactPerson = contactPerson;

PhoneNumber phone1 = new PhoneNumber();
phone1.CountryCode = phone1CCode;
phone1.Value = phone1Val;
phone1.Extension = phone1Ext;
custAddress.Phone1 = phone1;

PhoneNumber phone2 = new PhoneNumber();
phone2.CountryCode = phone2CCode;
phone2.Value = phone2Val;
phone2.Extension = phone2Ext;
custAddress.Phone2 = phone2;

PhoneNumber phone3 = new PhoneNumber();
phone3.CountryCode = phone3CCode;
phone3.Value = phone3Val;
phone3.Extension = phone3Ext;
custAddress.Phone3 = phone3;

Policy customerPolicy = GPServ.GetPolicyByOperation("UpdateCustomerAddress",context);

// Choose whether to update an existing address, or create a new one

try{

if(AddUpdate == "Update")
GPServ.UpdateCustomerAddress(custAddress, context, customerPolicy);
if (AddUpdate == "Add")
GPServ.CreateCustomerAddress(custAddress, context, customerPolicy);
return true;
} catch(Exception e)
{
return false;
}
}




Now all that needs to be done is to hook up my Add / Update method to my InfoPath form. I chose to add it as a query web service – as it returns a Boolean result that I can check in the form to show success or failure.



And Presto – An InfoPath 2007 form getting and updating data in GP 10. Of course, there is no reason now why we can't publish the form to InfoPath Forms Services.

Conclusions

As for business use – this method can be highly useful, as we can allow other non-GP staff to interact with the system. With further customization, it could suit the following scenarios:
  • Expenses Form?
  • Stock Item Creation?
  • Customer Management?

And of course, as we are using InfoPath if we hook into SharePoint too we can create approval processes for these forms to be approved before they are submitted to GP.


Resources

Cheers all:-
davros

Tuesday, 11 November 2008

Creating a Global Theme using a single CSS stylesheet

Lately I've been working on a lot of SharePoint branding – for MOSS and WSS. For a consistent user experience, we need to brand the application pages too (/_layouts/…), so we create a custom theme.

There are many other articles about creating custom themes:

One of the pain points with developing your own theme comes when it has been rolled out across many sites, and then a snag is spotted, or something needs to be changed. The theme has to be updated, and re-applied everywhere it was used (since applying a theme in a site takes a copy of the CSS and supporting files and stores it in each site). Imagine having to do that across 50+ sites – it is certainly something that can make you cry.


To get around this, and allow us to make global changes post-deployment, I use the following method.

  1. Copy an existing theme, and make the necessary changes to the files to make it your own and customise the CSS (the above articles cover this) – and there is a theme generator out on the web: (http://hermansberghem.googlepages.com/themegenerator.htm)

  2. Somewhere in the root of your SharePoint system, create a blank CSS page – "MyTheme.css".

  3. Cut the CSS from your new theme on the server, and paste it into MyTheme.css.

  4. Go back to your CSS sheet on the server, remove all the text from it, and enter only the following line:
    @import:url('/MyTheme.css');

  5. Save + Reset IIS

Presto – now, all your custom theme does is look at a single parent style sheet in the root of your SharePoint system. This means that even after it's been deployed across many sites, we can make a change to the parent style sheet and see it reflected everywhere.


Hope this helps…davros.



SharePoint makes me cry...

Hello all -

I'm David (davros), and I work as a SharePoint + InfoPath consultant @ ISC Software Solutions (MS Gold Partner - http://www.isc-software.com/).


Recently I have come across a few things in SharePoint that have damn well near reduced me to tears. So, after finding work arounds and drying my eyes - I thought I would try and share them here, perhaps to help others avoid some of the pain.


I have been mainly working in the following areas of late:

  • SharePoint branding + customisation

  • InfoPath - custom task pane / dynamic form creation / etc

  • InfoPath Forms Services

I have recently completed the two MCTS exams for configuring SharePoint.

Anyway - hopefully some of my thoughts will be of use to someone....

.davros.