How do you expose the state of a SharePoint Workflow instance? - sharepoint

I have a fairly straight-forward sequential approval workflow that has an EnableModificationActivity that is in scope for just about the entirety of the workflow. My modification form is an ASPX page that gives the user the ability to enable/disable approval steps that have not occurred yet in the workflow. Since the workflow is able to be modified multiple times, I would like to the form to reflect the current state of the workflow, meaning it should show which activities are currently enabled or disabled.
I have come up with a clunky solution for this that I will share a little later on, but I have got to believe there is a clean way to go about this.

So here is the approach I ended up taking...
I created a Plain Old CLR Object (POCO) class specific for holding state information my particular workflow that is capable of being XML Serialized. I'll call this the "State Object" going forward.
I created a reusable class called "WorkflowStateManager" that is capable of loading and saving single State Objects for a given SPWorkflow. This class is accessible by both the workflow and the modification form.
Save State Implementation:
XML serializes the object to a string
Sets the serialized string on the SPWorkflow list item's property bag and calls the property bag's Update() method
Load State Implementation (Essentially the reverse of the Save State implementation)
Gets the serialized string from the SPWorkflow list item's property bag
XML Deserialize the string into the State Object
When the workflow is activated, I construct a new State Object, initialize various properties on it, and save it using the WorkflowStateManager.
As the workflow progresses, I load and update the State Object as needed in the following manner:
Use the WorkflowStateManager to load the current State Object
Make workflow decisions based on the State Object's values
Make desired changes to the State Object
Use the WorkflowStateManager to save the State Object
Now, my modification form is also able to load, manipulate, and save the State Object using the WorkflowStateManager, and in turn expose the current state of the workflow to the user.
I hope this might be of benefit to someone.

Related

Initial Core Data entities

My application is document based and uses Core Data. I want to create some initial entities when a new document is created. I use NSEntityDescription.insertNewObject, but then the document is considered edited and there is an action that can be undone an redone. How do I prevent this?
Set your document's undoManager to nil (keep a reference to it) before inserting your boilerplate objects, then set it back.

What is ment by attaching an entity to a context?

I've learned that entities are classes that represent the tables inside a database schema. But on this link they speak of an entity being tracked (attached) by the context
http://msdn.microsoft.com/en-us/data/jj592676.aspx
Added: the entity is being tracked by the context...
Do they speak of the objects/instances of entity's (so the classes) getting tracked by Entity Framework? Or literally the entity itself? I'm confused.
In one of my webapplications I am using this code, does it say all instances of FinalStudyDecision are in the modified state, or just the object fsd?
context.FinalStudyDecisions.Attach(fsd);
context.Entry(fsd).State = EntityState.Modified;
Or does this code just do it for one single object?
ObjectStateManager.ChangeObjectState(fsd, EntityState.Modified);
When an entity is attached to a context, the context "knows" the object and starts tracking its changes.
Normally, an entity is attached to a context when it is fetched from the database, e.g. by context.FinalStudyDecisions.Single(x => x.Id == 1) (if there is an item with Id == 1 of course).
But if you've got an existing FinalStudyDecisions that is not known by a context you can use the Attach method to make it known. This usually happens when an object is serialized to and subsequently deserialized from a web client.
If you attach an object to a context its state (EntityState) is Unchanged, so often you will change its state to Modified when you receive it back from a web client. This will trigger EF to store the object when SaveChanges is called.
Both
// DbContext API
context.Entry(fsd).State = EntityState.Modified;
and
// ObjectContext API
ObjectStateManager.ChangeObjectState(fsd, EntityState.Modified);
only change the state of the fsd object.
Important: if you Add an object to a context, either by setting its state Added or by adding it to a DbSet (or ObjectSet), not only fsd but also all its child objects are changed to Added.

Custom Control Custom Methods?

I have been making good use of custom properties withing custom controls. Is there such thing as custom methods? Say I want something to happen in a CC. A good example is the show method of the dialog box extension. If I have a cc with a extension dialog inside, I want my custom control to have a Show method which insulates the end user programmer from the extension pages Shoe method.
Is there anyway to do this?
At runtime, all Custom Control elements become instances of the UIIncludeComposite class; as such, there are many built in methods that you can call against any given control instance, but there is no way to specify custom methods, as opposed to custom properties.
There are, however, at least two ways you could achieve the result you're after:
Convert your Custom Control to a component (this NotesIn9 episode describes the simplest approach to this process). Once you've migrated the class that Designer generated to one that won't get overridden every time you build your NSF, you can add custom methods without fear that the next build will just wipe them out again. Since Custom Controls are essentially just IBM's implementation of the JSF 2.0 notion of "composite components", you could also create a component from scratch that has the same behavior as your existing Custom Control but also supports custom behavior. Note that either approach does not necessarily require that you create an OSGi library... you can define these components directly in an NSF; you only need to push them to a library if you want to reuse them across multiple NSFs without having to copy the various files to each.
In the custom properties for your control, include one property that accepts an API object. In other words, you could create any object (say, a Java class or SSJS object) that supports the custom methods you wish to define, and pass that object to the control. You could then call those methods by getting a handle on the object via the CC's property map.
For example:
<myCC id="myCustomControl" API="#{someObject}" />
Assuming whatever #{someObject} resolves to includes a show() method, you can call that method by getting a handle on the instance that has been passed to the control:
var cc = getComponent("myCustomControl");
var ccProperties = cc.getPropertyMap();
var ccAPI = ccProperties.get("API");
ccAPI.show(cc);
In the above example, I'm passing the actual Custom Control to the show() method, because the object itself isn't aware of the Custom Control it was passed to. So if that method needs to get a handle on its children to toggle their rendered property, for example, then it needs some other way of determining its context.
Tim's solution with passing in the object is a great solution to that.
Just something that popped into my head, would be easy to make a property similar to the rendered property on a control. Pass in a value and inside the custom control do something based on its value ie. if true display dialog, else hide, in the XPage during run time modify this value and partial refresh the control, the logic will be re run by this and the control will display etc.
Another solution could be to include a JavaScript library in your custom control providing functions (your custom control methods) where you'd have to pass in the id of the custom control instance.

Restore one fetched entity out of many -- Core Data

This question covncerns my lack of understanding of how to use the core data undo manager and how to restore a NSManagedObject to its state before editing was done.
I am just learning my way around Core Data. I have my NSManagedObject classes set up with their dynamic accessors. I perform a fetch that returns several NSManagedObject entity results. Content from each of these entity results (first name, last name) get put into a table view, and then the user picks one out of the table for detailed view and then editing.
The detail view controller receives a pointer to the selected NSManagedObject entity. As the user edits the fields, the corresponding property value in the NSManagedObject entity is updated. This seemed like the cleanest way to manage these changes.
Now, rather than committing the changes using save, I want to provide a cancel-editing feature that rolls back to what is in the data base for that entity. I really only want to restore the one entity and not perform the entire refetch.
I tried rollback and I tried NSUndoManager (with beginUndoGrouping and endUndoGrouping), and that is not working. I don't think I understand what rollback is really supposed to do.
But in any case, I still want to restore the property values in just that single entity (taking the lazy approach to only fetch what is needed, which is the one entity) so that my detail view controller can refill its view with the correct information. Right now it is using the NSManagedObject entity values, which contain the edited values, which were cancelled.
I suppose I could just start the edit process by creating a copy of the NSManagedObject. If the cancel-editing button is pressed, I could copy it back into the original. (I might even be able to just replace the original with the copy by moving the pointer. But since the pointer has actually been passed through several objects, I'm not sure how to manage the retain number on the copy.)
Does anyone have any other suggestions?
Thanks
Using rollback should accomplish what you want and I'm not sure what it doesn't. It is probably an implementation detail error.
You can find the specific managed object/s that were updated but not yet saved by calling the context's updatedObjects.

Core Data: Design questions. Object wrappers or not?

I'm designing my first project using Core Data (for iPhone) and Im having some issues that might be related with my design approach.
I'm doing an application that allows the user to create an Order (let's say for a restaurant).
I'm using the graphic designer to model my persistence object (i.e. OrdeMO). I add MO to the ead of each name to indicate its a Managed Object.
I use XCode to create the Managed Object Class automatically.
I have created some "DAO" classes that allows you to search or create a new object in the Managed Context.
Now to my problem.
I want to create an OrderMO object to store the order the user is creating, BUT I don't want it to be part of the context until the user actually places it.
I tried creating the object with [OrderMO alloc] but the object I get is "incomplete" and when I try to set any of its attribute I get an error.
I'm assuming the problem is that I need to create the order IN the context in order to use it. Is that so?
I have considered various options:
Create the object in the context and the user rollback if the user discards the order. The problem is that the user might save other context object during the process (like his prefs) so this doesn't work. Is there a way to create the object "inside a separate transaction" of sorts?
Create a wrapper object that will hold the same data as the MO, and then only create the MO when the user place the order. The downside of this is that I have to maintain a new class.
Create an attribute in the MO, such as "placed", and use to filter my searches in the context. The problem with this one is that I will end up with "trash" objects in the domain (i.e. unplaced orders) and I will have to do some cleanup from time to time...
Do I have any other choice?
Any suggestion is appreciated.
Thanks (for reading this long post!)
Gonso
You should create the OrderMO object in the managed object context and then delete it if the user decides not to place the order.
If the context is saved before the object is deleted, the "trash" object will be deleted from the persistent store on the next save (if the context wasn't saved, the "trash" object will never be saved to the persistent store).
The flag to determine if the order was placed or not does not have to live in the OrderMO object as you suggest in option 3. It could be in the view controller that is tracking the order(s) that are being edited. And, again, you won't have "trash" objects because they will have been deleted.

Resources