Friday, 22 February 2013

CreateTaskWithContentType (05)

Let's make this work

1.) Open up the elements file of your workflow, you should see something along the lines of:
<?xml version="1.0" encoding="utf-8" ?>
 
<!-- Customize the text in square brackets. 
Remove brackets when filling in, e.g.
Name="[NAME]" ==> Name="MyWorkflow" -->
 
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Workflow
     Name="SPM_Workflow"
     Description="My SharePoint Workflow"
     Id="d702d3ec-d6ab-4c34-9e73-5b8dcb0599ce"
     CodeBesideClass="WorkflowProject1.Workflow1.Workflow1"
     CodeBesideAssembly="$assemblyname$">
    <Categories/>
    <MetaData>
      <AssociationCategories>List</AssociationCategories>
      <!-- Tags to specify InfoPath forms for the workflow; delete tags for forms that you do not have -->
      <!--<Association_FormURN>[URN FOR ASSOCIATION FORM]</Association_FormURN>
       <Instantiation_FormURN>[URN FOR INSTANTIATION FORM]</Instantiation_FormURN>
      <Task0_FormURN>[URN FOR TASK (type 0) FORM]</Task0_FormURN>
      <Task1_FormURN>[URN FOR TASK (type 1) FORM]</Task1_FormURN>-->
      <!-- Modification forms: create a unique guid for each modification form -->
      <!--<Modification_[UNIQUE GUID]_FormURN>[URN FOR MODIFICATION FORM]</Modification_[UNIQUE GUID]_FormURN>
      <Modification_[UNIQUE GUID]_Name>[NAME OF MODIFICATION TO BE DISPLAYED AS A LINK ON WORKFLOW STATUS PAGE</Modification_[UNIQUE GUID]_Name>
      -->
      <StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
    </MetaData>
  </Workflow>
</Elements>
we're going to add two things to this
  • our content type
  • our task form ID (remember way back in the first post I said make a note of it.)
ok so when done we should have something along the lines of

<?xml version="1.0" encoding="utf-8" ?>
 
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Workflow
     Name="SharePoint Magic WF"
     Description="My SharePoint Workflow"
     Id="d702d3ec-d6ab-4c34-9e73-5b8dcb0599ce"
     CodeBesideClass="SPM_WorkFlow.Workflow1.Workflow1"
     CodeBesideAssembly="$assemblyname$"
     TaskListContentTypeId="0x01080100d6b5580b746b4e68b032f3cdc88b6062">
    <Categories/>
    <MetaData>
      <AssociationCategories>List</AssociationCategories>
      <Task0_FormURN>urn:schemas-microsoft-com:office:infopath:SPM-Form:-myXSD-2013-02-21T15-34-28</Task0_FormURN>
      <StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
    </MetaData>
  </Workflow>
</Elements>

deploy this, and you should be OK.

CreateTaskWithContentType (04)

Let's Make a Workflow 

1.) Open up that workflow you created in the very first post, and let's have a look


Right after the onWorkFlowActivated activity add the following:
  • LogToHistoryListActivity
  • CreateTaskWithContentType
  • create a WhileActivity
    • Inside the while activity add a onTaskChanged activity
  • right outside the while activity add a complete task activity
  • finally create another Log To History Activity
2.) Now don't panic you should have four red Exclamation marks on your workflow, this is normal; all you've done was drag and drop some shapes onto a canvas. This isn't Visio and you're not a Business Analyst, you're actually going to have to do some real work and not draw shapes with a crayon calling it a career.

createTaskWithContentType1

Lets get started, click on the createTaskWithContentType1 activity and hit the F4 key to bring up the properties.

Create a correlationToken, type in the value TaskToken and pick Workflow1 as the OwnerActivity Name. That should get rid of your Exclamation mark, but we're not done we're going to have to do some binding.

First bind the ContentTypeId to a custom field, how you ask?

click on the property to give it focus, this should bring up three little dots on the left of the value field, click that

this will bring up the "Bind 'Content TypeId' to an Activity's Property" dialogue box, select the "Bind to a new member" tab, Change the name to something meaningful, switch the type to Create Field or don't, it doesn't really matter.


with that complete hit OK, you have two more properties to bind, follow the same procedure as above

  • For the TaskId property, I set the field name to Task_Id
  • For the TaskProperties property, I set the field name to Task_Properties

Now for the MethodInvoking property just type in createTask and hit enter, that should bring you to the bound function createTask, here you're going to set your task properties, the value for your task id field.
the three task properties you're going to set are:
  • Assigned to - who does the task
  • Title - what the task is called
  • TaskType - which task form to use (it'll become clearer later on)

so here's what you're function is suppose to look like when complete as well as the fields you created

public String Task_ContentTypeId = default(System.String);
public Guid Task_Id = default(System.Guid);
public SPWorkflowTaskProperties Task_Properties = new Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
 
private void CreateTask(object sender, EventArgs e)
{
    Task_Id = Guid.NewGuid();
 
    Task_Properties.AssignedTo = @"domain\SPtest3";
    Task_Properties.Title = "Magical Task";
    Task_Properties.TaskType = 0;
}


and here's what the properties of your activity should be

Next we're going to tackle the onTaskChanged activity

Set your CorrelationToken property to the same one as for createTaskWithContentType1, TaskToken.

When it comes to binding your TaskId property, do NOT create a new field, bind to the existing one from before.


Next you have to bind the BeforeProperties property to a new field, I call it Task_beforeProperties, it's good practice to bind the AfterProperties as well, but not necessary for an example this simplistic.


With your on task changed activity wrapped up lets focus on that while loop.

Click on your while loop, hit F4 to see the properties, change the Condition property to Code Condition and call the Condition CheckText and hit enter.


once you hit enter you should see the function in the code behind, now this function has a ConditionalEventArgs that can be set to a boolean value representing if it should loop or not.
  • True = loop
  • False = exit loop
As the name of our function suggests we're going to ensure that our task user provides us with a value and we're going to accomplish this by checking our kiwiMango Field. the code to do this is as follows.

private void CheckText(object sender, ConditionalEventArgs e)
{
    e.Result = Task_BeforeProperties.ExtendedProperties["KiwiMango"] == null ? true : 
        string.IsNullOrEmpty(Task_BeforeProperties.ExtendedProperties["KiwiMango"].ToString());   
}

Or if you prefer

private void CheckText(object sender, ConditionalEventArgs e)
{
    if (Task_BeforeProperties.ExtendedProperties["KiwiMango"] == null)
    {
        e.Result = true;       
    }
    else if (Task_BeforeProperties.ExtendedProperties["KiwiMango"].ToString() == string.Empty)
    {
        e.Result = true;
    }
    else
    {
        e.Result = false;
    }
}

We're going to set up our complete task.


  • Again set the correlation Token to TaskToken
  • Bind the task Id like you did before
  • Now you could set your TaskOutcome property to static text such as Task complete, but let's do something more interesting. instead in the methodInvoking property type in completeTask and hit enter; this should bring you back to your code behind an here we'll set the task outcome to include our value from our form.


private void completeTask(object sender, EventArgs e)
{
    ((CompleteTask)sender).TaskOutcome = 
        string.Format("KiwiMango = {0}", task_BeforeProperties.ExtendedProperties["KiwiMango"].ToString());
}

now what you've done is cast the sender argument to a CompleteTask activity and then set the taskOutcome property in code to include the parameter passed back from the user form.

Log activities

To wrap this post up lets set up our two log activities, so that we can know what on earth is going on, the first one lets set it to let us know that:
  • the work flow has started
  • we're about to create a task
the second one:
  • the task is complete
  • workflow is complete
to do this, right click on the first one and select Generate handlers, this will bring you to the code behind where, we'll add our code. As with the complete task activity we're going to cast our sender as a LogToHistoryActivity object and set our history description and history outcome properties
the code for the first log is

private void logToHistoryListActivity1_MethodInvoking(object sender, EventArgs e)
{
    ((LogToHistoryListActivity)sender).HistoryDescription = "workflow initiated";
    ((LogToHistoryListActivity)sender).HistoryOutcome = "about to create task";
}

and for the second log is

private void logToHistoryListActivity2_MethodInvoking(object sender, EventArgs e)
{
    ((LogToHistoryListActivity)sender).HistoryDescription = "Task Complete";
    ((LogToHistoryListActivity)sender).HistoryOutcome = "about to Complete workflow";
}

and there you go, if you deploy and attach your workflow it's going to fail, but that's cause we're not done yet; it's now time for the real pain in the ass part, making the damn thing work. but that's in the next post.

continued

Thursday, 21 February 2013

CreateTaskWithContentType (03)



  • Create a Workflow Project (part 01)
  • Create Custom Task List (part 02)
  • Create a Custom InfoPath form (part 03)
  • Create a Workflow utilizing the CreateTaskWithContentType (part 04)
  • Set up your workflow to work (part 05)

  • Build a Custom InfoPath Form

    1.) Create a blank form that looks like the following:
    there really only is two controls on it, that's a text box and a button. Make sure you pick blank form on the file tab.

    2.) give your field a very descriptive name like kiwimango; goto the Data Tab and hit show fields
    this will bring up a tree view for your fields, rename the default value to something descriptive, don't use kiwimango...
    You probably should change your group name to something other than myFields, but hey do as I say not as I do.

    3.) let's set up that Go button, right click on it and hit Button Properties.

    click submit options, This will bring up the submit options dialogue box.

    check off  "Allow users to submit this form", select hosting environment from the drop down. Add a main submit.

    4.) Go to to File->Info->Form Options (Advanced form options)

    5.) Once The Form Options dialogue pops up, select Security and Trust, remove the check from "Form template requires the following level of trust from the user:", now I Change it to full trust, but it should work with domain (and is probably a better practice).

    5.)Save the form like you would any regular document in MS office, but choose the name wisely. Pick something that's descriptive but not what you're going to want in your visual studio project.

    6.) Once you've saved your document, publish it to a network location, File-> Publish, click Network Location.

    7.) This will start your publishing wizard, the first two steps are:

    • pick a network location to publish to. (where the file is saved locally) 
    • give your form a template name. 


    8.) Next you're going to be given the path to your file you just published, just clear that sucker out and leave it blank, then hit next. (no image for this step provided)

    9.) If you followed instructions you should get the following

    If you didn't get something along these lines, go back and remove that path in step two, otherwise hit publish, then close.

    10.) Now you have to add your published form to your Visual Studio Project. Right click your workflow item and add existing item.
    11.) After the form is added you have to change the deployment type of the InfoPath form to ElementFile, just click on your form and hit the F4 key on your keyboard.


    12.) With that complete, make sure your workflow1 (or whatever you've named it) is included in the feature, while you're in that neighbourhood, there are two buttons at the bottom Left of that screen, Design and Manifest, hit the manifest one. in the manifest click the edit options, below is more or less what you should see.

    in the edit window you're going to paste the following

    <?xml version="1.0" encoding="utf-8" ?>
    <Feature xmlns="http://schemas.microsoft.com/sharepoint/" ReceiverAssembly="Microsoft.Office.Workflow.Feature, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" ReceiverClass="Microsoft.Office.Workflow.Feature.WorkflowFeatureReceiver">
      <Properties>
        <Property Key="GloballyAvailable" Value="true" />
        <Property Key="RegisterForms" Value="Workflow1\*.xsn" />
      </Properties>
    </Feature>
    
    
    Make sure that your RegisterForms property has the correct path, if you changed it from the default Workflow1 make sure you reflect that change here. also I remind you this is for share point 2010, if you're dealing with 2007 change the version to 12.0.0.0 and there may be something else i wouldn't know cause I've only recently jumped on the SharePoint band wagon. and I think it's 15.0.0.0 for SP2013

    One thing to note, is that if you have a Custom feature receiver it will no longer work.

    Deploy your project, and continued in my next post.

    Continued

    Wednesday, 20 February 2013

    CreateTaskWithContentType (02)

    Create Custom Column(s)

    Why would we make a custom site column? Why would you use the CreateTaskWithContentType activity if we didn't need custom columns. If you do not need a custom column, use the CreateTask activity.

    1.) If you're still with me let's make a custom field/column whichever you prefer to call it. right click your project->Add->New Item->Empty Element

    Make sure you have a SharePoint 2010 template selected in the left hand pane and pick the Empty Element Type in the centre pane, give it a name and click Add.

    2.) Once you've added an empty element Item to your project define your column(s) as needed. I'm creating just one since this is not an exercise in defining site columns.
    <?xml version="1.0" encoding="utf-8"?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
      <Field ID="{8F1F2378-C7F1-4D1B-BD4B-8F3951ECCB7D}"
             Name="spm_KiwiMango" 
             Group="Custom Workflow" 
             DisplayName="Kiwi Mango"
             Type="Text" 
             Sealed="FALSE" 
             ReadOnly="FALSE" 
             Hidden="FALSE"
             DisplaceOnUpgrade="TRUE"/>
    </Elements>
    
    that's mine make yours however you like.

    Create Content Type for tasks

    1.) Now you've probably made lots of content types, but for the love of god do not skip this part. To get started add a content type. Right click your project->Add->New Item
    again make sure to have the SharePoint 2010 Template selected, pick the content type Object type give it a name  and click Add.

    2.) When prompted which base type should this content type inherit from? select task

    3.) This is what you get out of the box.
    what you want it to look like is the following
    <?xml version="1.0" encoding="utf-8"?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
      <!-- Parent ContentType: Task List (0x01080100) -->
      <ContentType ID="0x01080100d6b5580b746b4e68b032f3cdc88b6062"
                   Name="spm_WorkFlow_CT"
                   Group="Custom Content Types"
                   Description="My Content Type"
                   Inherits="TRUE"
                   Version="0"
                   Hidden="FALSE">
        <FieldRefs>
          <FieldRef ID="{8F1F2378-C7F1-4D1B-BD4B-8F3951ECCB7D}" Name="spm_KiwiMango" />
        </FieldRefs>
        <XmlDocuments>
          <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
            <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
              <New>_layouts/WrkTaskIP.aspx‌​</New>
              <Display>_layouts/WrkTaskIP.aspx</Display>
              <Edit>_layouts/WrkTaskIP.aspx</Edit>
            </FormUrls>
          </XmlDocument>
        </XmlDocuments>
      </ContentType
    
    </Elements>
    Not exactly your run of the mill content type. Things of note are
    • Inherit from the base type 0x01080100
    • Set the hidden attribute to false
    • Add your field ref
    • Specify a generic place holder for the forms, do this so that when we make the list definition the workflow doesn't use the OOTB (out of the box) forms. (FormUrls Schema Overview)
    Wowzers looks like we're done with the content type. Next lets make us a list definition(again there's a trick to it, so don't stop paying attention.

    It's List Definition Time

    1.) Start like you would with any list definition from content type, right click your project->Add->New Item
    Now as always make sure you have SP2010 template selected in the left hand pane, in the centre pane pick "List Definition From Content Type", give it a much more descriptive name then I did and hit Add.

    2.) Next you'll be prompted to enter in a couple of details about your list definition a display name, which content type to use and whether to include a list instance.
    So give your list definition a name, pick your content type, and well I never like to include my list instance with my list definition so I guess do what I'm doing or don't...

    3.) Now open up your List Definitions elements file.
    change the Type property to 107, this will define it as a task list

    4.) Now with that complete you can open up the schema to inspect the difference you're content type made
    It's not all that interesting but hey why not right?

    5.) Declare a List Instance from the list Definition you just created. As always, right click your project-> Add Item->New
    SP2010 template, List instance item, Descriptive name, Hit Add.

    6.) Next you're going to have some list instance details to fill out.
    Give it a name, make sure to select your List Definition, clean up the URL, if you want add it to the quick launch that's you're call or should be in your governance (whatever that is).

    7.) Next deploy your solution, navigate to your root web and check on your list. if there's nothing there, then open up your feature and make sure that you include your columns, content type, list definition and list instance, the work flow is not necessary just yet.

    http://[your site]:[your port number]/_layouts/viewlsts.aspx

    now you should see something along the lines of

    If you see a magical task list, having the clipboard icon with the check mark you where successful, if you have the list but the wrong icon go back to your list definition and change the type to 107, then go to your list instance and change the TemplateType attribute to 107, redeploy and check again. if you don't have the list start over I guess....

    Continued

    Tuesday, 19 February 2013

    CreateTaskWithContentType (01)

    Creating a Task with a custom content type turned out to be a nightmare... I'm putting this together so that it doesn't become a reoccurring one. There are seven steps to pushing through this kerfuffle.

    Create a Workflow Project

    It doesn't really matter whether you make a sequential or state machine workflow; a State Machine workflow will add it's own level of complexity, but since this post is focusing on the CreateTaskWithContentType activity I'm going to create a sequential to simplify this example as much as possible.

    1.) Add a Sequential workflow project to your solution. Right click your solution->Add->New Project.

    2.) Next, pick your site with port number and you shouldn't have a choice but too deploy as a farm solution.

    3.) Now you have to name your workflow and select whether it's a list or a site, I'm going with List though I'd imagine it shouldn't make a difference, but don't quote me on that.

    4.) At this final junction you'll basically have two choices, either specify all your details or do it manually later, since the whole point of this series of posts is to create your own custom task list with custom content type it doesn't  make too much sense to define them now. Disable the automatic association.


    WOOT WOOT, you've just created your sequential workflow project, feel great? you shouldn't it's only going to get worse from here on in.

    Continued in Part 02; creating Site Columns, Content Type, List Definition, List Instance.