Monday, January 21, 2013
SharePoint 2010 MySite en Windows 8
Exportar ítems de listas de SharePoint 2007 a SharePoint 2010
SharePoint 2010 y el modelo de objetos del lado del cliente con JavaScript
SharePoint 2010 es 99% personalizable
http://desarrollo.topgroup.com.ar/2013/01/sharepoint-2010-es-99-personalizable.html
Utilizando las WebParts de SharePoint
Implementación de Branding usando Sharepoint
Thursday, May 24, 2012
SharePoint 2010 LookUp Error
- Habiendo detectado el problema, se deberá desproteger y editar en modo avanzado el formulario ASPX donde se presenta el error utilizando SP Designer 2010. Para este caso es el formulario NewForm y EditForm.aspx. El primero permite crear un nuevo comentario, y el segundo Editar uno existente.
- Suponiendo que vamos a usar NewForm.aspx, luego de la etiqueta de cierre </WebPartPages:ListFormWebPart> de la WebPart ListFormWebPart, se debe adicionar una WebPart de Editor de Contenido Web.
- Guarde la página NewForm.aspx y ábrala en su navegador Web, y ponga en modo de Edición la página.
- En este momento puede agregar contenido a la WebPart de Editor de Contenido. En ese momento agregue el siguiente código JavaScript.
$(document).ready(function () {
var columnName = "Noticia";
OverrideDropDownList(columnName);
function OverrideDropDownList(columnName) {
var lookupDDL = new DropDownList(columnName);
if (lookupDDL.Type == "C") {
lookupDDL.Obj.css('display', 'none');
lookupDDL.Obj.next("img").css('display', 'none');
// Construct the simple drop down field with change trigger
var tempDDLName = "tempDDLName_" + columnName;
if (lookupDDL.Obj.parent().find("select[ID='" + tempDDLName + "']").length == 0) {
lookupDDL.Obj.parent().append("<select name='" + tempDDLName + "' id='" + tempDDLName + "' title='" + tempDDLName + "'></select>");
lookupDDL.Obj.parent().find("select[ID='" + tempDDLName + "']").bind("change", function () {
updateOriginalField(columnName, tempDDLName);
});
}
var splittedChoices = lookupDDL.Obj.attr('choices').split("|");
var hiddenVal = $('input[name=' + lookupDDL.Obj.attr("optHid") + ']').val()
if (hiddenVal == "0") {
hiddenVal = lookupDDL.Obj.attr("value")
}
lookupDDL = new DropDownList(tempDDLName);
for (var i = 0; i < splittedChoices.length; i++) {
var optionVal = splittedChoices[i];
i++;
var optionId = splittedChoices[i];
var selected = (optionId == hiddenVal) ? " selected='selected'" : "";
lookupDDL.Obj.append("<option" + selected + " value='" + optionId + "'>" + optionVal + "</option>");
}
}
}
function updateOriginalField(child, temp) {
var childSelect = new DropDownList(child);
var tempSelect = new DropDownList(temp);
childSelect.Obj.attr("value", tempSelect.Obj.find("option:selected").val());
var hiddenId = childSelect.Obj.attr("optHid");
$('input[name=' + hiddenId + ']').val(tempSelect.Obj.find("option:selected").val());
}
function DropDownList(colName) {
if ((this.Obj = $("select[Title='" + colName + "']")).html() != null) {
this.Type = "S";
} else if ((this.Obj = $("input[Title='" + colName + "']")).html() != null) {
this.Type = "C";
} else if ((this.Obj = $("select[ID$='SelectCandidate'][Title^='" + colName + " ']")).html() != null) {
this.Type = "M";
} else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$=': " + colName + "']")).html() != null) {
this.Type = "M"; } else this.Type = null; } }); </script>
Wednesday, May 02, 2012
Control de Campo Personalizado en SharePoint 2010
La respuesta a este interrogante se conoce como los controles personalizados en SharePoint. Que es un mecanismo que permite que se puedan agregar tipos de campo especializados, que pueden ser reutilizados como cualquier tipo de columna, en listas o bibliotecas.
Esta entrada está dedicada a esa opción que SharePoint ofrece a través de programación .NET. Pongamos manos a la obra, y veamos cómo se puede implementar algo como una columna de tipo picker que nos ayude a mejorar la experiencia de usuario. La siguiente imagen muestra dicho campo en funcionamiento:
En la imagen anterior se apreciaran claramente 2 campos que utilizan el control que desarrollaremos en esta entrada: Thumbnail y Url Video. La idea es poder seleccionar una imagen o un video y que en el campo respectivo quede asociada la URL a dicho recurso.
- Crea un proyecto de SharePoint nuevo basado en la plantilla de Proyecto de SharePoint vacío.
- Cuando se haya creado tal proyecto adicionar una clase por cada tipo de campo personalizado que se piense crear.
{
public AssetUrlSelectorField(SPFieldCollection fields,string fieldName) : base(fields, fieldName)
{}
string typeName, string displayName) : base(fields, typeName, displayName)
{}
public override BaseFieldControl FieldRenderingControl
{
get
{
BaseFieldControl control = new AssetUrlSelectorFieldControl();
control.FieldName = base.InternalName;
return control;
}
}
}
La clase AssetUrlSelectorField define el tipo de campo personalizado que vamos a utilizar en el desarrollo del control. Es muy importante y obligatorio implementar los dos constructores públicos, que son requeridos por SharePoint Foundation. Finalmente para este caso específico se ha sobrescrito una propiedad que esencialmente se encarga de retornar el control que definiremos en otra clase.
class AssetUrlSelectorFieldControl : BaseFieldControl
{
protected AssetUrlSelector urlSelector;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Set the value if this is a postback.
if (this.Page.IsPostBack)
{
try
{
this.ListItemFieldValue = urlSelector.AssetUrl;
}
catch (Exception ex)
{
EventLog log = new EventLog();
if (!(log.Source == "Mi Log"))
log.Source = "Mi Log";
log.WriteEntry("Error en el Método OnLoad: " + ex.Message + "- InnerException: " + ex.InnerException + "- Source: " + ex.Source + "- StackTrace: " + ex.StackTrace,
EventLogEntryType.Error, 1);
throw;
}
}
}
protected override void CreateChildControls()
{
base.CreateChildControls();
// Add the asset picker when in edit mode.
try
{
urlSelector = new AssetUrlSelector();
this.Controls.Add(urlSelector);
}
catch (Exception ex)
{
EventLog log = new EventLog();
if (!(log.Source == "Mi Log"))
log.Source = "Mi Log";
log.WriteEntry("Error en el Método CreateChildControls: " + ex.Message + "- InnerException: " + ex.InnerException + "- Source: " + ex.Source + "- StackTrace: " + ex.StackTrace,
EventLogEntryType.Error, 1);
throw;
}
}
public override object Value
{
get
{
this.EnsureChildControls();
return urlSelector.AssetUrl;
}
set
{
this.EnsureChildControls();
urlSelector.AssetUrl = (string)this.ItemFieldValue;
}
}
}
La clase anterior es la que se ha invocado inicialmente en la clase AssetUrlSelectorField, en la propiedad sobrescrita FieldRenderingControl. Esta clase aprovecha la clase AssetUrlSelector la cual es la que provee la funcionalidad de tipo picker usada en SharePoint por defecto. Para mayor información de dicha clase se puede consultar su documentación en MSDN http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.publishing.webcontrols.asseturlselector.aspx
Para evitar confusiones, los namespaces utilizados en las clases mostradas son:
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.WebControls;
using System.Web.UI;
using System.Diagnostics;
Con las clases definidas, muy fáciles de entender por cualquier desarrollador a continuación se requiere de la creación y definición de un archivo XML que al momento de hacer el despliegue de la solución en el servidor de SharePoint permite identificar el control que podrá ser utilizado dentro del sitio que se requiera o esté disponible la característica. SharePoint 2010 mantiene estos archivos XML en la ruta TEMPLATE/XML, en la cual muchos de sus tipos de campo están definidos. El nombrado de dicho archivo debe comenzar con el nombre fldtypes_, y de ahí se completa acorde a cada necesidad, en este caso por ejemplo: fldtypes_AssetUrlSelectorCustomField.xml. El contenido de este archivo XML que debemos agregar manualmente al folder mapeado XML, se presenta a continuación:
<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
<FieldType>
<Field Name="TypeName">AssetUrlSelectorField</Field>
<Field Name="ParentType">Text</Field>
<Field Name="TypeDisplayName">Picker</Field>
<Field Name="TypeShortDescription">Picker de Activos</Field>
<Field Name="UserCreatable">TRUE</Field>
<Field Name="ShowOnListCreate">TRUE</Field>
<Field Name="ShowOnSurveyCreate">TRUE</Field>
<Field Name="ShowOnDocumentLibraryCreate">TRUE</Field>
<Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
<Field Name="FieldTypeClass">
WebParts.AssetUrlSelectorCustomField.AssetUrlSelectorField,$SharePoint.Project.AssemblyFullName$
</Field>
</FieldType>
</FieldTypes>
La definición <Field Name="FieldTypeClass">
WebParts.AssetUrlSelectorCustomField.AssetUrlSelectorField,$SharePoint.Project.AssemblyFullName$
</Field> puede variar acorde a su implementación, por ejemplo el nombre del namespace, en este caso WebParts, que usted haya usado en su proyecto en Visual Studio .NET.
En general la solución debería verse así:
El título Picker de Activos es el que se definió en el valor de la propiedad TypeShortDescription.
En conclusión, aunque no se cuenta con una experiencia de desarrollo 100% definida en VS.NET 2010, los pasos para desarrollar un control de campo personalizado y un campo personalizado base, no son complejos, y realmente son la puerta a implementaciones mucho más avanzadas que permitan con mayor facilidad cumplir requerimientos de nuestros clientes, que suelen salirse de los límites de la funcionalidad por defecto de la Plataforma.
Tuesday, March 27, 2012
Información Interesante y de Valor para el día a día
Seguidamente de SolidQ, un artículo muy bueno, bastante detallado sobre la aplicación de servicios de Web Analytics http://www.solidq.com/sqj/es/Pages/2011_September_Issue/Practicas-recomendadas-de-SharePoint-Creacion-y-configuracion-de-aplicaciones-de-servicio-con-y-sin-PowerShell-parte-2.aspx
Feliz lectura.
Tuesday, March 20, 2012
No se puede representar el formulario. Esto puede deberse a un problema en la configuración del Servicio de estado de Microsoft SharePoint Server
- Navegue a la Administración Central
- Haga clic en la opción Asistente de Configuración o Configuration Wizards
- Inicie el asistente
- Deberá solicitarsele que active el State Service, podría ya estar seleccionada, así que clic en Siguiente.
- Salte el paso de configurar un nuevo Sitio. Puede aparecer un Error. Si vuelve a correr el Wizard y vuelve a saltarse la creación del Sitio verá que el Wizard finaliza correctamente.
- Haga clic en el botón Finish
Ahora es momento de intentar nuevamente crear el WorkFlow de Aprobación de SP 2010.
Felíz WF!!
Friday, March 16, 2012
La validación del esquema encontró errores que no son de tipo de datos
El error original es el siguiente:
Microsoft.Office.InfoPath.Server.SolutionLifetime.SchemaValidationException: La validación del esquema encontró errores que no son de tipo de datos. en Microsoft.Office.InfoPath.Server.SolutionLifetime.SchemaValidation.Validate(Document document, XPathNavigator subtreeToValidate, XmlOperation operation) en Microsoft.Office.InfoPath.Server.DocumentLifetime.XmlNotificationManager.NodeChangedHandler(Object sender, DomEventArgs e) en Microsoft.Office.InfoPath.Server.Xml.DomEvents.FireQueuedEvents() en Microsoft.Office.InfoPath.Server.Xml.DomEvents.AtomicEvent.System.IDisposable.Dispose() en Microsoft.Office.InfoPath.Server.Xml.XPath.InfoPathXPathNavigator.SetValue(String value) en Microsoft.Office.InfoPath.Server.Xml.XPath.XPathNavigatorHost.<>c__DisplayClass1.
La propuesta está en esta dirección, gracias a Share Notes por compartirla:
Solución
Felíz solución.
Friday, March 02, 2012
Implementando una WebPart XSLT en SharePoint Server 2010
Una de las características importantes con las que cuenta SharePoint, que puede considerarse como uno de sus pilares, son las WebParts, o conocidas también como Elementos Web.
Estos elementos Web permiten esencialmente desplegar información, la cual típicamente se encuentra almacenada en listas o bibliotecas de SharePoint. Pueden haber otras fuentes de datos, pero no son interés de esta entrada por ahora. Vamos a mostrar cómo usar una WebPart que consume información de una lista o biblioteca, y por medio de XSLT, manipular dicha información para mejorar el aspecto gráfico de la WebPart que por defecto, despliega la información de manera tabular, y con una presentación poco familiar para usuarios finales. Suponiendo que tenemos una biblioteca de activos multimedia en SharePoint Server 2010, vamos agregarla a una página de contenido que llamaremos XSLT.aspx, como un Elemento Web para desplegar los videos que ahí se han dado de alta.
- Lo primero que hacemos es crear la página de contenido como una página de publicación o de elementos web. Luego editarla en modo avanzado en SharePoint Designer 2010.
- A continuación agregamos en la zona correspondiente, a través de las siguientes opciones una vista de datos vacía: Insertar – Vista de Datos – Vista de Datos Vacía.
- En este momento se debe poder visualizar una opción que permite seleccionar la fuente de datos para la vista de datos, la cual en este caso, será la biblioteca de activos multimedia. SharePoint Designer despliega una ventana que permite seleccionar de entre las listas y bibliotecas disponibles. En este caso tenemos una biblioteca llamada Videos.
En la imagen se pueden observar los siguientes elementos:
La vista de datos vacía que se acaba de insertar en código se interpreta como<WebPartPages:DataFormWebPart><DataFields>
</DataFields>
</WebPartPages:DataFormWebPart>En la ventana de Selector de Orígenes de Datos se puede observar la biblioteca que se quiere usar como fuente, en este caso Videos.
- En este momento se puede seleccionar la biblioteca Videos y hacer clic en el botón Aceptar. En ese instante se debe activar la ventana Detalles del origen de datos, la cual despliega todos los campos disponibles en la biblioteca de Videos. En este caso vamos a desplegar el Título y el Thumbnail (Vista previa de la dirección URL de la imagen) asociados a cada ítem dentro de la biblioteca. Seleccionando los 2 campos al tiempo se puede proceder a arrastrar y soltar dichos campos en la WebPart agregada previamente.
- Hasta este momento contamos ya con una DataFormWebPart conectada a una biblioteca llamada Videos, como fuente de datos. Ahora si se explora el código generado en SharePoint Designer, se aprecia que se tiene el tag <XSL>, lo cual indica que esta WebPart viene ya lista para ser modificada a través de dichos elementos.
Se puede observar que ya se han agregado los campos Título y el Thumbnail como un elemento IMAGE. Si se hace clic sobre los campos se puede apreciar que son totalmente modificables como elementos HTML.
<td class="ms-vb">
<xsl:value-of select="@Title"/>
</td>
<td class="ms-vb">
<img border="0" src="{@AlternateThumbnailUrl}"alt="{@AlternateThumbnailUrl.desc}"/>
</td>Es momento entonces de realizar los cambios necesarios para que los elementos queden mejor organizados. Para esto vamos a requerir de una hoja de estilos personalizada con las siguientes clases:
.comun { font-size: 12px; line-height: 16px; margin: 0 0 13px; }
.comun h3,
.comun h4 { font-family: "Myriad Pro", sans-serif; text-align: left; }
.comun h3 a,
.comun h4 a { color: #00a2ec; font-size: 11px; font-weight: normal; }
.comun h3 { color: #003b71; font-size: 21px; line-height: 23px; padding: 10px 13px 7px; }
.comun h4 { color: #003b71; font-size: 15px;}
.comun h3 small,
.comun h4 small { margin: 0 0 0 6px; }
.comun small { color: #232323; font-size: 11px; font-style: italic; }
.comun a { color: #00a2ec; text-decoration: none; }
.comun a:hover { text-decoration: underline; }
.comun a small { color: #00a2ec; }
.comun p { margin: 0 0 7px; }
.comun ul { color: #0053a1; list-style-type: disc; margin: 0 0 10px 15px; }
.comun li { margin: 0 0 7px; }
.lateral { background: #fff url("lateral.gif") repeat-x left bottom; border: 1px solid #cbe3ab; width: 255px; }
.lateral h4 { background: #cbe3ab; border: 1px solid #e6e6e6; padding: 7px 13px; }.contenido { padding: 10px 13px; }
.fix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
* html .fix { zoom: 1; } /* IE6 */
*:first-child+html .fix { zoom: 1; } /* IE7 */.ver_mas { border-top: 1px dotted #b3b4b4; margin: 5px 0 0; padding: 7px 0 0; text-align: right; }
#video {}
#video ul { list-style-type: none; margin: 0 0 10px; }
#video li { color: #4f4e4e; }
#video img { border: 1px #2664a9 solid; float: left; margin: 0 7px 0 0; width: 76px; }En la ruta de Activos del sitio se puede crear una carpeta llamada CSS y ahí crear un archivo, por ejemplo, estilos.css, donde se debe copiar el código anterior.
Luego de eso en la página maestra del sitio, de puede hacer referencia a la hoja de estilos así:
<SharePoint:CssRegistration name="/SiteAssets/CSS/estilos.css" After="corev4.css" runat="server"/>
- Teniendo una hoja de estilos lista, es momento de aplicar los estilos a la WebPart que ya habíamos agregado para desplegar los videos. Lo primero que se debe ubicar es la siguiente sección de código:
<xsl:template name="dvt_1.rowview">
<tr>
<xsl:if test="position() mod 2 = 1">
<xsl:attribute name="class">ms-alternating</xsl:attribute>
</xsl:if>
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<td class="ms-vb" width="1%" nowrap="nowrap">
<span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
</td>
</xsl:if>
<td class="ms-vb">
<xsl:value-of select="@Title"/>
</td>
<td class="ms-vb">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</td>
</tr>
</xsl:template>
Este código debe entonces quedar así:
<xsl:template name="dvt_1.rowview">
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
</xsl:if><li class="clearfix">
<a href="#">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</a>
<p><xsl:value-of select="@Title"/></p>
</li>
</xsl:template>
- Seguido entonces se debe ubicar la siguiente sección en el código:
<xsl:otherwise>
<table border="0" width="100%" cellpadding="2" cellspacing="0">
<tr valign="top">
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<th class="ms-vh" width="1%" nowrap="nowrap"></th>
</xsl:if>
<th class="ms-vh" nowrap="nowrap">Título</th>
<th class="ms-vh" nowrap="nowrap">Vista previa de la dirección URL de la imagen</th>
</tr>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows"/>
<xsl:with-param name="FirstRow" select="1" />
<xsl:with-param name="LastRow" select="$LastRow - $FirstRow + 1" />
</xsl:call-template>
</table>
</xsl:otherwise>
Se debe reemplazar por lo siguiente:
<xsl:otherwise>
<div class="comun lateral" id="video">
<h4>Videos</h4>
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<th class="ms-vh" width="1%" nowrap="nowrap"></th>
</xsl:if>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows"/>
<xsl:with-param name="FirstRow" select="1" />
<xsl:with-param name="LastRow" select="$LastRow - $FirstRow + 1" />
</xsl:call-template>
</div>
</xsl:otherwise>
- Luego de los cambios anteriores, se debe tener lo siguiente en modo de diseño en SharePoint Designer.
Como se puede observar no se tiene una imagen asociada al video. Pero suponiendo que no se tiene una imagen cargada, se puede hacer lo siguiente para usar la imagen por defecto de los videos que SharePoint ofrece.
- Seleccione en la página en modo de diseño en SharePoint Designer la imagen que debe verse así en código.
<a href="#">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</a>Se debe cambiar por lo siguiente:
<xsl:if test="@AlternateThumbnailUrl != ''">
<a href="#">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</a>
</xsl:if>
<xsl:if test="@AlternateThumbnailUrl = ''">
<a href="#">
<img border="0" src="/_layouts/images/VideoPreview.png" alt="Video"/>
</a>
</xsl:if>Se aprecia que cargaría una imagen por defecto en caso de que no se haya cargado un thumbnail asociado al video. En ese caso una imagen perteneciente al conjunto de imágenes de SharePoint 2010, llamada VideoPreview.png. Debe estarse viendo así la WebPart en el diseñador:
- Finalmente se guardan los cambios, y se puede visualizar el preview de la página XSLT.aspx a través del navegador Web, con lo que se tiene lo siguiente:
Por ahora esta entrada ha cumplido su objetivo, la tarea siguiente sería que podamos hacer clic en la imagen del video, pero que tenga asociada la URL al video y este se despliegue, por ejemplo en la misma página o en una nueva página. Para tener una idea pueden remitirse a una entrada donde se habla de algo similar, para tener más ideas.
Feliz WebPart XSLT rediseñada.
Friday, November 25, 2011
Aprobar una Tarea Programáticamente
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.Utilities;
using System.Collections;
using System.Globalization;
namespace WSPBuilderCOA
{
public partial class EditTask : System.Web.UI.UserControl
{
private string url;
public string Url
{
set
{
url = value;
}
get
{
return url;
}
}
protected void Page_Load(object sender, EventArgs e)
{
//this.lblMensaje = "";
}
protected void btnAprobar_Click(object sender, EventArgs e)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(url))
{
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
try
{
SPList task = web.Lists["Tareas"];
SPListItem item = task.Items.GetItemById(Convert.ToInt32(Request.Params["ID"]));
if (item["WorkflowListId"] != null)
{
Guid sourceListID = new Guid(item["WorkflowListId"].ToString());
SPList sourceList = web.Lists.GetList(sourceListID, true);
int sourceListItemID = Convert.ToInt32(item["WorkflowItemId"]);
SPListItem sourceListItem = sourceList.GetItemById(sourceListItemID);
//El primer aprobador realiza la tarea y cambia el estado del ítem a Aprobado en Primera Instancia
if (sourceListItem["Aprobador"].ToString() == "Aprobador 1" && Convert.ToString(sourceListItem["Estado"]) == "En Revisión")
{
sourceListItem["Estado"] = "Aprobado en Primera Instancia";
sourceListItem["Aprobador"] = "Aprobador 1";
sourceListItem.Update();
//Get the workflow instance id from Task item
Guid taskWorkflowInstanceID = new Guid(item["WorkflowInstanceID"].ToString());
SPWorkflow workflow = item.Workflows[taskWorkflowInstanceID];
SPWorkflowTask wfTask = workflow.Tasks[item.UniqueId];
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.Completed] = "TRUE";
ht["Completed"] = "TRUE";
ht[SPBuiltInFieldId.PercentComplete] = 1.0f;
ht["PercentComplete"] = 1.0f;
ht["Status"] = "Completed";
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)wfTask.Web.Language, false), Strings.WorkflowStatusInProgress, new object[0]);
ht[SPBuiltInFieldId.WorkflowOutcome] = "Approved";
ht["TaskStatus"] = "Approved";
ht["FormData"] = SPWorkflowStatus.InProgress;
SPWorkflowTask.AlterTask((wfTask as SPListItem), ht, true);
Response.Redirect(Request.Params["Source"]);
}
else
{
if (sourceListItem["Aprobador"].ToString() == "Aprobador 1" && Convert.ToString(sourceListItem["Estado"]) == "Aprobado en Primera Instancia")
{
sourceListItem["Estado"] = "Aprobado en Segunda Instancia";
sourceListItem["Aprobador"] = "Aprobador 2";
sourceListItem.Update();
//Get the workflow instance id from Task item
Guid taskWorkflowInstanceID = new Guid(item["WorkflowInstanceID"].ToString());
SPWorkflow workflow = item.Workflows[taskWorkflowInstanceID];
SPWorkflowTask wfTask = workflow.Tasks[item.UniqueId];
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.Completed] = "TRUE";
ht["Completed"] = "TRUE";
ht[SPBuiltInFieldId.PercentComplete] = 1.0f;
ht["PercentComplete"] = 1.0f;
ht["Status"] = "Completed";
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)wfTask.Web.Language, false), Strings.WorkflowStatusInProgress, new object[0]);
ht[SPBuiltInFieldId.WorkflowOutcome] = "Approved";
ht["TaskStatus"] = "Approved";
ht["FormData"] = SPWorkflowStatus.InProgress;
SPWorkflowTask.AlterTask((wfTask as SPListItem), ht, true);
Response.Redirect(Request.Params["Source"]);
}
}
}
}
catch (Exception ex)
{
//lblMensaje.Text = "Ha ocurrido un error aprobando: " + ex.Message + " - " + ex.Source;
}
finally
{
web.AllowUnsafeUpdates = false;
}
}
}
});
}
protected void btnRechazar_Click(object sender, EventArgs e)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(url))
{
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
try
{
SPList task = web.Lists["Tareas"];
SPListItem item = task.Items.GetItemById(Convert.ToInt32(Request.Params["ID"]));
if (item["WorkflowListId"] != null)
{
Guid sourceListID = new Guid(item["WorkflowListId"].ToString());
SPList sourceList = web.Lists.GetList(sourceListID, true);
int sourceListItemID = Convert.ToInt32(item["WorkflowItemId"]);
SPListItem sourceListItem = sourceList.GetItemById(sourceListItemID);
//El primer aprobador realiza la tarea y cambia el estado del ítem a Aprobado en Primera Instancia
if (sourceListItem["Aprobador"].ToString() == "Aprobador 1" && Convert.ToString(sourceListItem["Estado"]) == "En Revisión")
{
sourceListItem["Estado"] = "Rechazado";
sourceListItem["Aprobador"] = "Aprobador 1";
sourceListItem.Update();
//Get the workflow instance id from Task item
Guid taskWorkflowInstanceID = new Guid(item["WorkflowInstanceID"].ToString());
SPWorkflow workflow = item.Workflows[taskWorkflowInstanceID];
SPWorkflowTask wfTask = workflow.Tasks[item.UniqueId];
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.Completed] = "TRUE";
ht["Completed"] = "TRUE";
ht[SPBuiltInFieldId.PercentComplete] = 1.0f;
ht["PercentComplete"] = 1.0f;
ht["Status"] = "Completed";
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)wfTask.Web.Language, false), Strings.WorkflowStatusInProgress, new object[0]);
ht[SPBuiltInFieldId.WorkflowOutcome] = "Approved";
ht["TaskStatus"] = "Approved";
ht["FormData"] = SPWorkflowStatus.InProgress;
SPWorkflowTask.AlterTask((wfTask as SPListItem), ht, true);
Response.Redirect(Request.Params["Source"]);
}
else
{
if (sourceListItem["Aprobador"].ToString() == "Aprobador 1" && Convert.ToString(sourceListItem["Estado"]) == "Aprobado en Primera Instancia")
{
sourceListItem["Estado"] = "Rechazado";
sourceListItem["Aprobador"] = "Aprobador 2";
sourceListItem.Update();
//Get the workflow instance id from Task item
Guid taskWorkflowInstanceID = new Guid(item["WorkflowInstanceID"].ToString());
SPWorkflow workflow = item.Workflows[taskWorkflowInstanceID];
SPWorkflowTask wfTask = workflow.Tasks[item.UniqueId];
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.Completed] = "TRUE";
ht["Completed"] = "TRUE";
ht[SPBuiltInFieldId.PercentComplete] = 1.0f;
ht["PercentComplete"] = 1.0f;
ht["Status"] = "Completed";
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)wfTask.Web.Language, false), Strings.WorkflowStatusInProgress, new object[0]);
ht[SPBuiltInFieldId.WorkflowOutcome] = "Approved";
ht["TaskStatus"] = "Approved";
ht["FormData"] = SPWorkflowStatus.InProgress;
SPWorkflowTask.AlterTask((wfTask as SPListItem), ht, true);
Response.Redirect(Request.Params["Source"]);
}
}
}
}
catch (Exception ex)
{
//lblMensaje.Text = "Ha ocurrido un error aprobando: " + ex.Message + " - " + ex.Source;
}
finally
{
web.AllowUnsafeUpdates = false;
}
}
}
});
}
}
}
