Create the Workflow Task Edit Form

При разработке собственных рабочих процессов, вам придётся самим программно создавать задания. При использовании Activity CreateTaskWithContentType, указывая тип контента, можно использовать свои формы инициации, ассоциации и редактирования для задания. В данной статье решил показать как создать форму для редактирования задания.

Создание формы

Открываем Visual Studio (я использую Visual Studio 2010) — Открываем “File Menu” — Выбираем “New” — Выбираем “Web Site” — Выбираем “ASP.NET Web Site” — Меняем тип на HTTP (это очень важно) — Выбираем местоположение: http://localhost/_layouts/AgreementTaskEditForm. IIS скопирует ваши файлы в директорию C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS

Создание проекта в Visual Studio

— Жмём “OK”, для создания. — Удаляем файлы About.aspx, Default.aspx и SiteMaster

— Создаём папку TaskEditForm. — Жмём на неё правой кнопкой и выбираем “Add New Item” — Выбираем “Web Form”     — Называем форму “TaskEditForm.aspx”     — Выбираем “Place code in separate file”     — Жмём “Add”

Добавление новой Web формы

После манипуляций проект выглядит как-то так:

Как выглядит проект

Добавляем вверху aspx файла:

<%@ Register TagPrefix="SharePoint" 
             Namespace="Microsoft.SharePoint.WebControls" 
             Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register TagPrefix="Utilities" 
             Namespace="Microsoft.SharePoint.Utilities" 
             Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Всё остальное удаляем. Добавляем:

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
 <%-- Начало кода контрола --%>
<%-- Конец кода контрола --%>
<%-- Тэг, который указывает SharePoint, что мы будем постить данные в форму--%>
    <SharePoint:FormDigest ID="FormDigest1" runat="server" />
</asp:Content>

Теперь внутрь управляющего коннтрола добавляем элементы управления, которые нам нужны. Более-менее в приличный вид для отображения приведём. В итоге файл выглядит примерно так:

<%@ Register TagPrefix="SharePoint" 
             Namespace="Microsoft.SharePoint.WebControls" 
             Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register TagPrefix="Utilities" 
             Namespace="Microsoft.SharePoint.Utilities" 
             Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register TagPrefix="spuc" Namespace="Microsoft.SharePoint.WebControls"
             Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="TaskEditForm.aspx.cs" Inherits="TaskEditForm_TaskEditForm" %>

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
<div id="ApproveForm" style="margin-left: auto; margin-top:50px; margin-right: auto; width:800px; ">
    
    <div id="DataField" style="  -moz-box-sizing: border-box;">
        <table id="DataT">
            <tr>
                <td style="width:200px;" class="DataTtd DataTLabelTd">
                    <p style="margin-right:20px; margin-left:20px;">Состояние:</p>
                     
                </td>
                <td class="DataTDataTd DataTtd" >
                    <asp:TextBox CssClass="tbx"
                        ID="TaskStatus" Width="500" runat="server" Text="" Enabled="false">
                    </asp:TextBox>
            
                </td>
            </tr>
          
            <tr>
                <td style="width:200px;" class="DataTtd DataTLabelTd">
                 <p style="margin-right:20px; margin-left:20px;">Срок выполнения:</p>
                </td>
                <td class="DataTDataTd DataTtd ">
                    <spuc:DateTimeControl Enabled="false"  runat="server" ID="DueDate" CssClassTextBox="DataTimePicerCSS" DateOnly="true" />
                </td>
            </tr>
            <tr>

                <td style="width:200px;" class="DataTtd DataTLabelTd">
                     <p style="margin-right:20px; margin-left:20px;">Примечание:</p>
                </td>
                <td class="DataTDataTd DataTtd ">
                    <asp:TextBox CssClass="tbx" ID="Note" 
                 runat="server" rows="5" TextMode="multiline" Text=""></asp:TextBox>
                </td>
            </tr>
        
        </table>
      
    </div>

    <div id="BtnsField">
    <asp:Panel ID="Btns_Panel" runat="server" >
   <asp:Button ID="btnApprove" onclick="btnApprove_Click" runat="server" Text="Утвердить" />
        &nbsp;
        <asp:Button ID="btnCancel" onclick="btnCancel_Click" runat="server" Text="Отмена" />
       
           </asp:Panel>
    </div>
    
</div>
<SharePoint:FormDigest ID="FormDigest1" runat="server" />
</asp:Content>

Где-то сверху css-стили добавим:

<style  type="text/css">   
     
        #DataT tr, #DataT, #DataTReAssigned, #DataTReAssigned tr
        {
            padding:0px;
            border-collapse: collapse;
        }
        #DataT
        
        .DataTtd
        {
            padding-bottom:10px;
            padding-left:0px;
            padding-right:0px;
            border-bottom: 1pt solid #D8D8D8;
            border-top: 1pt solid #D8D8D8;
            
        }
        .DataTDataTd
        {
            background-color: #F5F6F7;
            width:600px;
        }
        
        .DataTLabelTd
        {
            width:200px;
        }
        
        .tbx, .DataTimePicerCSS
        {
            -moz-box-sizing: border-box;
    font-family: Times New Roman;
    font-size: 12pt;
    font-style: normal;
    font-weight: normal;
    text-align: left;
    white-space: normal;
    width: 500px;
    margin-left:20px;
        }
        #ctl00_PlaceHolderMain_Author_upLevelDiv, #ctl00_PlaceHolderMain_AssignedToPE_upLevelDiv
        {
            height:20px !important;
            width:500px;
            border: 1px solid #828790;
            padding-top: 5px;
             margin-left:20px;
        }
        #ctl00_PlaceHolderMain_FileUpload1
        {
            margin-left:20px;
        }
        #BtnsField, #BtnsFieldReAssigned
        {
            border-left: 1pt solid #D8D8D8;
            border-right: 1pt solid #D8D8D8;
            border-bottom: 1pt solid #D8D8D8;
            padding-top:15px; 
            text-align:center;
            padding-bottom:20px;
        }
      
        
    </style>

Написание кода для формы

Форма редактирования вне проекта рабочего процесса. Поэтому необходимо использовать внешние методы для работы со списками и заданиями. Для начала подключаем соответствующие библиотеки:

using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.Utilities;

Вы увидите так же методы для обработки действий кнопок и метод, вызывающийся при загрузке страницы:

protected void Page_Load(object sender, EventArgs e)
{
    
}
protected void btnCancel_Click(object sender, EventArgs e)
{

}
protected void btnApprove_Click(object sender, EventArgs e)
{
}

Они то и реализуют всю магию. Но для начала необходимо переменные для работы определить.

#region переменные задания

protected SPList _TaskListAttachedTo;   // список задания рабочего процесса
protected SPListItem _TaskListItem;    // список в задании
protected string _myTaskData;           // данные от юзера, которые посланы в р.б.
string _paramTaskListItemID;          // ID Task List Item 

#endregion

#region параметры рабочего процесса

string _paramSPListGuid = string.Empty;   // GUID списка, с которым заатачились
SPWorkflow _activeWorkflow;       // Текущий р.б. 
Guid _workflowInstanceGuid;        // Айдишник р.б.
public Microsoft.SharePoint.Workflow. SPWorkflowActivationProperties workflowProperties =
        new Microsoft.SharePoint.Workflow. SPWorkflowActivationProperties();
#endregion

Получение параметров рабочего процесса

Для начала нам необходимо параметры получить.

 private void getWorkflowParameters()
    {
        this._paramSPListGuid = Request.Params["List"];     // The SharePoint Document Libary ID
        this._paramTaskListItemID = Request.Params["ID"];   // The associated Task Lists ID
    }

Загрузка MasterPage

//   Переопределение метода. Запускатеся при иницилазации.
//   ммм...здесь программно можно задать, какой мастер юзать
protected override void OnPreInit(EventArgs e)
{
    base.OnPreInit(e);  
        
    // Текущая страница
    string pageName = Page.AppRelativeVirtualPath.Substring(
                Page.AppRelativeVirtualPath.LastIndexOf('/') + 1);

    // Если в десижнере
    if (pageName.Substring(0, 6).ToUpper() == "Design".ToUpper())
    {
          
        this._myPoratlSite = new SPSite("http://localhost/");
        SPControl.SetContextSite(Context, this._myPoratlSite);

        this._myTeamSite = SPControl.GetContextWeb(Context).Webs["Site1"];
    }
    else
    {
        this._myTeamSite = SPControl.GetContextWeb(Context);
        this.MasterPageFile = _myTeamSite.MasterUrl;    
    }
        
}

Получение информации о списке и рабочем процессе

Теперь необходимо получить параметры рабочего процесса и задания.

private void getTaskListInformation()
{
    // Получаем Task List that, к которму приатачены
    this._TaskListAttachedTo = this._myTeamSite.Lists[new Guid(this._paramSPListGuid)];

    // Получаем Task Item Object, который WF создал
    this._TaskListItem = this._TaskListAttachedTo.GetItemById( System.Convert.ToInt16(this._paramTaskListItemID));

    // Получаем ID Workflow Instance
    this._workflowInstanceGuid = new Guid(Convert.ToString( this._TaskListItem["WorkflowInstanceID"]));

    this._activeWorkflow = new SPWorkflow(this._TaskListItem, this._workflowInstanceGuid);
    
}

Получение информации из списка

Теперь, когда нам известна общая информация о списке и рабочем процессе, можно получить информацию о нашем конкретном задании.

private void getTaskInformation()
{
    // Получаем статус
    if (this._TaskListItem["ows_Status"] != null)
    {
        TaskStatus.Text = this._TaskListItem["ows_Status"].ToString();
    }
    // Получаем информацию о сроках
    if (this._TaskListItem["ows_DueDate"] != null)
        DueDate.SelectedDate = Convert.ToDateTime( this._TaskListItem["ows_DueDate"]);
   

    // Получаем комментарий
    string sNote = GetParam("ows_Note");
    if (sNote != string.Empty)
        Note.Text = sNote;
}

Добавляем в Page_load метод

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
        RBList.SelectedIndex = 0;
    getWorkflowParameters();    
    getTaskListInformation();   
    getTaskInformation();       
}

Методы для обработки действий кнопок

Осталось лишь написать методы, которые будут обрабатывать действия кнопок.

// Отмена
protected void btnCancel_Click(object sender, EventArgs e)
{
    // просто делаем редирет в библиотеку   
    SPUtility.Redirect( this._TaskListAttachedTo.DefaultViewUrl,         
                            SPRedirectFlags.UseSource,
                            HttpContext.Current);
}

// При утверждении
protected void btnApprove_Click(object sender, EventArgs e)
{
        
    Hashtable taskHash = new Hashtable();
    taskHash["Result"] = "Утвёрждён";    // кастомное поле "Результат"
    taskHash["PercentComplete"] = "1";    // 1 = 100%.  .9 = 90%
    taskHash["Note"] = Note.Text;          // кастомное поле "Примечание"
    // обновляем информации о задании
    SPWorkflowTask.AlterTask(this._TaskListItem, taskHash, true);

    
    SPUtility.Redirect( this._TaskListAttachedTo.DefaultViewUrl,         
                        SPRedirectFlags.UseSource,
                        HttpContext.Current);
        
}

По аналогии можно новые элементы на форму добавлять. Теперь необходимо тип контента свой создать (который мы завяжем на эту форму), чтобы в рабочем процессе при создании указать наш тип контента с нашей формой редактирования.