Where an issue will arise is that supported method for saving records in silverlight is using either the SOAP or OData web services and the service model for silverlight is a asynchronous model. This would mean the processes would appear as follows:
- Save button is clicked.
- Save is triggered on silverlight control
- Form save is under taken
- Form is refreshed.
Because of this I have tried a number of options with no success, these include:
- Creating a javascript wait method to loop until the silverlight control is finish. The issue with this method is that the javascript and silverlight control utilise the same thread and thus all you do is cause the browser to hang indefinitely.
- Putting a wait condition on the main thread within silverlight after the async process has started and to continue waiting until the process is complete. The issue with this is the browsers main thread and the silverlight main thread are one and the same so there is nothing to tell the control that the time interval has elapse and to check again. This will also cause the browser to hang.
- Attempt to wrap the whole process up to "fake" a synchronous process. This would cause the browser to appear to hang untill the process was complete. This would partially work but not a friendly user experience.
Process is as follows:
- User clicks save button.
- Javascript calls exposed method on silverlight control.
- Silverlight control checks if anything needs saving. If so...
- Provide feedback to user that control is saving.
- Cancel the save event on the form using the "preventDefault" method provided.
- Record the save method used to save using the "getSaveMethod" JScript method.
- Save the silverlight information.
- Set the silverlight control to "clean"
- Based on the save method call the JScript "save" method on the form.
Example silverlight code:
[ScriptableMember] public bool Save(object Context) { // only save a dirty control if (IsDirty && _AllowSave) { bsyIndicator.BusyContent = "Saving Changes..."; bsyIndicator.IsBusy = true; ((dynamic)Context).preventDefault(); _SaveMode = (Constants.SaveMode)int.Parse(((dynamic)Context).getSaveMode().ToString()); // save the dirty control _recordHelper.Save_Complete += SaveComplete; _recordHelper.SaveRecord(record); return false; } IsDirty = true; return true; }
private void SaveComplete(object sender, EventArgs e) { // do nothing on callback bsyIndicator.IsBusy = false; IsDirty = false; // call save again dynamic xrm = HtmlPage.Window.GetProperty("Xrm"); switch(_SaveMode) { case Constants.SaveMode.Send: xrm.Page.data.entity.save(); break; case Constants.SaveMode.SaveClose: xrm.Page.data.entity.save("saveandclose"); break; case Constants.SaveMode.SaveNew: xrm.Page.data.entity.save("saveandnew"); break; case Constants.SaveMode.SaveCompleted: case Constants.SaveMode.Deactivate: // this is unsupported HtmlPage.Window.Invoke("SaveAsCompleted"); break; default: xrm.Page.data.entity.save(); break; } _RecordHelper.Save_Complete -= SaveComplete; }
Example JScript Code:
ExecuteSilverlightMethod = function (context, controlName, namespace, methodName) { var controlObj = Xrm.Page.ui.controls.get(controlName); silverLightControl = controlObj.getObject(); eval("silverLightControl.Content." + namespace + "." + methodName + "(context.getEventArgs());"); }