domingo, 30 de mayo de 2010

Segmento de Código en SharePoint: Como obtener el login Name de los asistentes de un sitio de reuniones

Quiero compartir con ustedes este segmento de código que pienso puede ser útil debido a que es algo engañoso el obtener los login Name de los asistentes.

Dentro del Sitio de Reuniones accedemos la lista de asistentes y utilizamos SPQuery para obtener la columna AssignedTo de dicha lista construyendolo a través de CAML como se muestra abajo:

image

Ejecutamos el query a través del metodo GetItems de la clase SPList y luego recorremos cada uno de los elementos que contiene que son cada uno de los asistentes. 

image

AssignedTo es de Tipo SPFieldUserValue si pasamos en el contructor el valor de la columna AssignedTo a dicho objeto.  Descubriremos que tiene una propiedad SPUser que nos dará el LoginName del asistente.  Y con eso obtenemos el LoginName del asistente que es como la llave única para validar el usuario contra el AD y otros valores que necesitemos.

Eso es todo amigos, si están interesados en personalizar los sitios de reuniones de SharePoint esta información les puede ser de utilidad.

Code4Fun!,

Manolo Herrera

jueves, 27 de mayo de 2010

Error en los espacios de trabajo de SharePoint g_InstanceID

Un error documentado por Microsoft.  Esto error muestra cuando hemos personalizado la Master Page y al parecer necesitamos agregar unas líneas para corregir el problema:

Síntoma:

Al intentar hacer clic sobre una de las fechas del lado izquierdo no nos lleva a ningún lugar y nos muestra en la barra de estado del explorador error.  Si hacemos clic sobre el nos muestra el siguiente error:

Message: 'g_instanceId' is undefined
Line: 4434
Char: 2
Code: 0

Solución:

Debe de modificar la Pagina maestra personalizada que esta utilizando agregando las siguientes dos líneas:

Abajo de la etiqueta <%@ Import Namespace="Microsoft.SharePoint" %>

aplique esta etiqueta:

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

abajo de la etiqueta <body>

<Meetings:PropertyBag runat="server"/>

La referencia del artículo es la siguiente:

http://blogs.msdn.com/b/spdsupport/archive/2008/03/24/how-to-fix-recurring-meeting-workspace-error-g-instanceid-is-undefined.aspx

Mis comentarios adicionales es luego de modificarla y subirla, no se olvide de publicarla y aprobar la publicación aplique de nuevo la Master Page al sitio o a la colección según sea el caso .

Nota: Agradezco a mi amiga y colega Emy Alegre por el tip.

SharePoint4Fun!,

Manolo Herrera

miércoles, 26 de mayo de 2010

Aplicando el patrón Passive View en un elemento Web en SharePoint - Parte II

En esta segunda parte (aquí la Primera parte) vamos a revisar el  Patrón Passive View aplicado al mismo elemento Web de la primera parte para que vea el cambio y como es este patrón una alternativa para tener un código mucho mas limpio y por ende mucho mas fácil de modificar o adaptar.

Passive View es una variación del popular patrón Model View Presenter.  Básicamente tenemos una vista tonta que lo único que sabe es mostrar la información toda la lógica de la vista esta en el presentador (o controlador) y este es el único que puede acceder el modelo. 

Aclaraciones:

En el siguiente código de ejemplo transfiero DTO’s a la vista para que la vista se encargue en el caso de una colección del binding .   No creo que este rompiendo el patrón por hacer esto, no encontré en la red ningún ejemplo que resolviera esto adecuadamente y no creo tampoco que el que la vista conozca un DTO este conociendo el modelo, simplemente es una forma muy practica de enlazar la data. Mas adelante muestro el ejemplo para que se comprenda mas este punto.

 

Infraestructura:

    1. Virtual Machine Windows Server 2003
    2. SQL Server 2005 Std Edition
    3. SharePoint Server 2007
    4. Visual Studio 2008 SP1
    5. WSPBuilder (para construir soluciones para SharePoint)

Empecemos:

Primero vamos a crear un elemento Web para SharePoint la herramienta a utilizar WSPBuilder, le vamos a llamar EditarTarea.

image

Luego crear un control de Usuario como la parte visual donde mostremos los controles de usuario (vea Primera parte).

image

Luego vamos a crear la interfase que representará la vista en el presentador inicialmente nos vamos a concentrar en como amarrar la vista con el control de usuario y el presentador.

La vista:

image .

La inyección de la vista en el presentador:

image

La implementación de la interfase en el control de usuario:

image

Continuamos ahora con los eventos declarándolos en la vista ya que es lo único que el presentador conoce de la vista

image

En el control de usuario implementamos dicha declaración amarrándolos con los eventos de los controles de usuario.

image

Ahora veamos como suscribimos los eventos en el presentador

image

La lógica de los eventos se define en el presentador, veamos algunos ejemplos:

image

Ahora vamos a ver las propiedades de la vista

image

Su implementación en el control de usuario

image

image

image

image

Su uso en el presentador es muy variado y dependerá de la lógica observe el siguiente ejemplo:

image

La meta en el presentador es mantener únicamente la lógica de la vista y separar las responsabilidades tanto de la vista como del modelo de tal forma que no tengamos dependencia de ninguna tecnología Web o de proveedor de datos. Esto lo podemos validar revisando los espacios de nombre utilizados en el presentador.  Como se  muestra abajo los usings del presentador:

image

Esto quiere decir que hemos encapsulado las referencias en el modelo o en la vista.  Cualquier cosa que necesitemos deberemos de invocarlo a través de propiedades, eventos y métodos a la vista o hacia el modelo. 

En el presentador hacemos la invocación de las dependencias hacia el modelo como lo muestro a continuación:

image

Revisemos algunas de sus dependencias como ha sido implementadas:

image

image

Como inicio la escritura del patrón de la siguiente forma:

  1. Creo el elemento Web con WSPBuilder en Visual Studio.
  2. Creo el control de usuario y desarrollo la parte visual.
  3. Finalizada la parte visual defino una Interfase que representa el control de usuario que finaliza con el sufijo Vista.
  4. Creo una clase con sufijo Presentador y coloco como parámetro la interfase de la vista para que sea inyectado definiendo un campo privado que representa la vista
  5. Implemento la vista en el control de usuario e inyectando la vista en el presentador en el evento OnInit().
  6. Luego empiezo declarando todos los eventos que me interesan atrapar del control usuario en la interfase de la vista e implementándolos en el control de usuario y en el presentador
  7. Continuo con las propiedades base que será los valores capturados por el usuario dentro de los controles.
  8. Inicio la lógica en el presentador y esto me va llevando a crear una nueva propiedad en la vista o a invocar el modelo definiendo interfaces y su implementación correspondiente encapsulando ésta responsabilidad en un servicio y repositorio. 

Resumen

El propósito de aplicar este patrón en nuestro desarrollo para elementos Web en SharePoint es fundamentalmente para mantener un código limpio que se traduce en una mejor lectura y comprensión del mismo para su mantenibilidad y que esta listo para ser probado ya que están bien separadas las responsabilidades.

Una vez comprendida las responsabilidades de cada uno de los actores dentro del patrón es mecánico el proceso de su codificación y no es para nada complicado.

Code4Fun!,

Manolo Herrera

martes, 25 de mayo de 2010

Resolviendo correctamente URL con apostrofes en elemento Web de SharePoint

Recientemente tuve que resolver un problema con URL.  El caso es el siguiente:

Un cliente esta acostumbrado a utilizar el apostrofe en el nombre del sitio y como es el mimo que utiliza para crear el URL en SharePoint entonces el GridView tenía un ItemTemplate dentro del el un LinkButton que tenía en la propiedad URLPostBack un Bind(‘URL’)

Algo como esto:

<asp:LinkButton id=”Enlace” runat=”server” URLPostBack=”<%# Bind(‘URL´)%>” />

Pero ASP.Net realiza un Encode del valor desplegado en el control y estaba convirtiendo el Apostrofe (‘) en una diagonal Apostrofe(/’). Entonces el IIS lo interpreta como otro sitio después de leer la diagonal y por consiguiente no encontraba la dirección. 

Si manualmente quitábamos la diagonal adicional el sitio era encontrado.

Solución:

Agregue el atributo ToolTip al control LinkButton agregando allí el Bind(‘URL’) y agregue el evento OnClick. 

 

<asp:LinkButton id=”Enlace” runat=”server” ToolTip=”<%# Bind(‘URL´)%>” OnClick=”Enlace_OnClick”/>

 

Del lado del servidor este fue el código que escribí:

protected void Enlace_OnClick(object sender, EventArgs e)

{

      LinkButton enlace = sender as LinkButton;

      if(enlace != null)

      {

             Response.Redirect(enlace.ToolTip,true);

      }

}

Y eso fue todo ya no altera el apostrofe incorrectamente y el sitio se abre correctamente.

Code4Fun!,

Manolo Herrera

sábado, 10 de abril de 2010

Finalmente he instalado SharePoint Fundation 2010 en mi Windows 7 Ultimate 64x Laptop

Configuración de mi portátil:

image

Experiencia de Instalación:

Preparase, yo demore dos días en instalar todo, mayormente por el enlace de Internet que tuve que repetir el descargar los Service Pack de SQL Server 2008 (400 Mb aprox.). No tuve que instalar el SQL Server 2008. SharePoint instaló por mi una instancia de SQL Server Express por mí. Me gusto la experiencia de no tener que preocuparme por el SQL Server.

Tuve que instalar manualmente los prerrequisitos, no fue muy difícil, pero tampoco agradable. Además tuve que cambiar un parámetro en el archivo de configuración del Setup del los bits de SharePoint que tuve que extraer nada complicada nada agradable tampoco. Presumiblemente esto es porque no es la versión final, eso espero.

Como fue instalada en Windows 7 la opción disponible es Stand Alone… bueno le diré si pensamos en tener un ambiente de desarrollo rápidamente esta bien, pero todo pasa tras bambalinas sin saber lo que esta haciendo. Le confieso que con WSS3.0 solo la hice cuando iniciaba mi carrera con SharePoint. Aquí prácticamente fui obligado si quería 2010 Instalado en mi máquina.

image

Luego tuve que bajar Visual Studio 2010 Ultimate RC1. Bueno esto fue otra demora de casi un día. Y solo Silverlight me reportó un error porque ya lo tenía instalado, pero de allí funcionó perfectamente. Seleccione lo que realmente quiere probar y ahórrese por lo menos un par de Gbs.

image

Experiencia de Uso:

Corre muy bien pero es la versión Fundation (antes WSS). Le confieso quise instalar la versión Server pero no me lo permitió, presumiblemente por la memoria RAM que necesita libres 4 GB.

Es muy familiar a la anterior, al principio le costará ubicar donde colocaron todo pero no con mucha dificultad, y luego se acostumbrará a ver el Ribbon que al final le ahorrará clics del ratón y encontrará la mayoría de operaciones que desea realizar. Siempre mire arriba y vera que cambia porque es contextual y muy familiar al ambiente de office 2010.

Desarrollar en Visual Studio 2010 en su laptop sin necesidad ya de instalar ninguna extensión o producto de terceros (aunque muy buenos como WSPBuilder) y tan solo presionar F5 para depurar su código VS se encarga de hacer el deployment hacer el attach process al Worker Process del IIS es toda una experiencia liberadora que llena de una agradable sonrisa de satisfacción. Solo debe de agregar el elemento Web en el lugar que desea hacerlo.

No olvide ejecutar el Visual Studio 2010 como administrador sino lo hace el se lo recordará pero para evitar dar mas vueltas no lo olvide.

Si desea que VS le habrá una página en especifico para depurar el elemento Web vaya a Propiedades del Proyecto y a la opción Debug. Seleccione la opción:

image

Recomendaciones:

Lea primero los enlaces de abajo que le sugiero y antes de siquiera empezar prepare todo para estar listo para instalar todo y así ahorrarse tiempo y frustraciones.

http://msdn.microsoft.com/en-us/library/ee554869(office.14).aspx (Sitio oficial de Microsoft, pero como siempre en un ambiente de laboratorio sin colocar los tropiezos que pueden encontrarse en un ambiente real).

http://blogs.msdn.com/bethmassi/archive/2009/12/02/setting-up-windows-7-for-office-sharepoint-2010-beta-development.aspx (Beth Massi da los tips necesarios para saltar los tropiezos y finalmente poseer La plataforma de Desarrollo de la empresa y el internet en sus manos).

Code4Fun!,

Manolo Herrera

jueves, 8 de abril de 2010

Aplicando el patrón Presentation Model como un estilo de programación en SharePoint Parte I (Estableciendo las bases)

Este patrón de presentación es una variación del famoso patrón MVP o Model View Presenter que ya ha sido descontinuado por el científico Martin Fowler.

En este artículo presentaré mas bien este patrón como un un estilo de programación mas que el simple argumento de hacer el código que este de una forma tal desacoplado que pueda probarlo o “testearlo” . Veo mas disfrutable el hecho de tener un código limpio, más fácil de mantener y adaptar a los cambios que es una constante en el desarrollo de software dejando optativo el escribir código para realizar las pruebas ya que no es el primordial incentivo.

Aclaraciones

El ejemplo utilizado esta orientado específicamente al desarrollo de elementos Web para SharePoint, aunque puede los conceptos y el estilo a otros entornos será una tarea que tendrá que realizar por si mismo.

No pretendo ser purista en mi exposición sino mas bien práctico y sistemático aplicando este patrón se adquiere una mecánica de trabajo como una línea de ensamblado donde ya esta predefinido el orden en que se encajan cada una de las partes.

Justificación:

Por qué se definieron los patrones de presentación debido a la complejidad que presenta el diseño de una pantalla y la lógica que requiere. Los dejo con un extracto de Martin Fowler sobre el problema que involucra el desarrollo de una interfaz de usuario:

  • Diseño de la pantalla: definiendo la localización de los controles en la pantalla y su jerarquía.
  • Lógica de la UI: Comportamiento que no es fácilmente programado dentro de los mismos controles.

Aplicando alguno de los patrones de presentación nos permite escribir la lógica que es completamente independiente de las vistas utilizadas para mostrar.

LVPM

Bauticemos este estilo de programación como LVPM que abrevia las palabras: Layout View Presentation Model, que reflejan la mecánica de trabajo de la siguiente forma:

Vamos a empezar diseñando el Layout de nuestra UI que luego nos permitirá abstraer una Interfaz de la Vista de los eventos que deseamos controlar que el usuario interactuará por medio de los controles definidos en la UI(Que en este caso en especifico es un control de usuario de extensión ascx). Siguiendo el patrón de presentación acoplaremos un Presentador que encapsulará toda la lógica de la UI y será responsable del estado de la Data representado a través de un Modelo, el cual a su vez abstraerá y separará responsabilidades según el modelo que hayamos definido del dominio a través de los patrones de servicios (que encapsula la lógica del dominio) y el repositorio (que encapsula el proveedor de los datos).

Recomendaciones preliminares:

No a la primera tenemos un diseño limpio y ajustado, habrán oportunidades de refactorización para delegar mejor las responsabilidades especialmente sobre el modelo que muchas veces es confusa y necesita de un análisis mas profundo.

No se estrese, relájese y hágalo de una forma natural comprendiendo una idea central sobre este estilo de patrones y es que el Presentador es el que manda a la vista y le dice cuando y que debe de hacer.

Por otro lado las Entidades del dominio y solamente esta parte del Modelo son de conocimiento publico entre estos 3 sujetos es la forma entre ellos se transfieren el estado del modelo. Ya que el Presentador no conoce nada acerca de los controles de la UI mas que solamente su interfaz denominada Vista.

Por el otro lado el Presentador no conoce las reglas del negocio ni que proveedor de datos esta utilizando el modelo para persistir su estado solo conoce la interfaz del modelo que encapsula internamente su propia lógica.

Resumiendo los pasos a seguir y siendo muy específicos al tema del desarrollo en SharePoint debería hacer lo siguiente:

1. Creo un elemento Web en mi Proyecto WSP en VS 2008 a través de WSPBuilder u otra herramienta disponible para crear soluciones para SharePoint dentro de VS 2008.

2. Creo un Control de Usuario de extensión ascx.

<%@ Assembly Name="Infoware.Portal.ReunionesV3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=60191eb7564e8d8f" %>
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="EditarTareaUserControl.ascx.cs"
    Inherits="Infoware.Portal.ReunionesV3.EditarTareaUserControl" %>

Para mas información sobre como envolver un control de usuario a un elemento web vea el siguiente enlace: http://jmhogua.blogspot.com/2010/02/comparando-procedimiento-de-creacion-de.html







3. Lo envuelvo en el elemento Web que hará de Wrapper de mi control de usuario.









 var userControlPath = "/_controltemplates/infoware/EditarTareaUserControl.ascx";
                try
                {
                    var editarTarea = Page.LoadControl(userControlPath);
                    Controls.Add(editarTarea);
                    base.CreateChildControls();
                }








4. Inicio diseñando el Layout de mi control de usuario incluyendo los eventos que deseo manejar.









image









5. Defino una Interfaz de la Vista que represente mi control de usuario e incluya cada evento de la UI que el usuario quiero que intervenga.









 public interface IEditarTareaVista
    {
        IList<Prioridad> ListadoPrioridad { set; }
        IList<Estado> ListadoEstado { set; }
        bool EsApoyo { get; set; }
        string URLReunion { get; set; }
        string URLOrigen { get; set; }
        string ObtenerParametro(string nombreLlave);
       
        string MensajeError { set; }
        string MensajeValidacionTitulo { set; }
        string MensajeValidacionAsignado { set; }
        string MensajeValidacionFechaInicio { set; }
        string MensajeValidacionFechaVencimiento { set; }
        string MensajeValidacionAvance { set; }
        bool HabilitarControles { set; }
        void RedireccionarPagina(string urlPagina);
        Tarea Tarea { get; set; }
        void HabilitarEdicionParcial();
        string Asignado { set; }
   }








6. Crearé una clase Presentador que estará acoplada al control de usuario para su instanciación.









La parte del presentador









image









La parte del control de usuario









image









7. Iniciaré acoplando cada evento del control de usuario con un método del presentador.









        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
                _presentador.FirstLoad();
            _presentador.OnLoad();
        }
        protected void AceptarTop_OnClick(object sender, EventArgs e)
        {
            AceptarInformacion();
        }
        protected void AceptarBottom_OnClick(object sender, EventArgs e)
        {
            AceptarInformacion();
        }
        private void AceptarInformacion()
        {
            var nuevaTarea = ObtenerInfoCapuradaPorLosControles();
            _presentador.PersistirCambioTarea(nuevaTarea);
        }
        private Tarea ObtenerInfoCapuradaPorLosControles()
        {
            var tareaEncontrada = new Tarea();
            if (CapturaAsignado.Accounts.Count > 0)
                tareaEncontrada.Asignado = CapturaAsignado.Accounts[0].ToString();
            decimal avance;
            if (!string.IsNullOrEmpty(CapturaAvance.Text)
                && decimal.TryParse(CapturaAvance.Text, out avance))
                tareaEncontrada.Avance = avance;
            tareaEncontrada.ModificadoPor = SPContext.Current.Web.CurrentUser.ToString();
            tareaEncontrada.FechaModificacion = DateTime.Now;
            tareaEncontrada.Descripcion = CapturaDescripcion.Text;
            tareaEncontrada.EsApoyo = EsApoyo;
            tareaEncontrada.EstadoActual = new Estado { Nombre = CapturaEstado.SelectedValue };
            if (!CapturaFechaInicio.IsDateEmpty)
                tareaEncontrada.FechaInicio = CapturaFechaInicio.SelectedDate;
            if (!CapturaFechaVencimiento.IsDateEmpty)
                tareaEncontrada.FechaVencimiento = CapturaFechaVencimiento.SelectedDate;
            tareaEncontrada.PrioridadAsignada = new Prioridad { Nombre = CapturaPrioridad.SelectedValue };
            tareaEncontrada.ReunionAsignada = new Reunion { URL = URLReunion };
            tareaEncontrada.Titulo = CapturaTitulo.Text;
            tareaEncontrada.NuevoComentario = CapturaComentarios.Text;
            tareaEncontrada.Comentarios = CapturaComentariosAnteriores.Text;
            return tareaEncontrada;
        }








8. Definiré la lógica dentro del presentador para cada notificación que haya invocado en el paso 7.









        public void FirstLoad()
        {
            _vista.ListadoPrioridad = _prioridadRepo.ObtenerListado();
            _vista.ListadoEstado = _estadoRepo.ObtenerListado();
            var valorTareaID = _vista.ObtenerParametro(_configuracionRepo.ParametroTareaID());
            _vista.URLOrigen = _vista.ObtenerParametro(_configuracionRepo.ParametroURLOrigen());
            if (!string.IsNullOrEmpty(valorTareaID))
            {
                Tarea tareaEncontrada = _tareaServicio.ObtenerPorID(ObtenerTareaID(valorTareaID));
                if (!string.IsNullOrEmpty(tareaEncontrada.Comentarios))
                    tareaEncontrada.Comentarios = tareaEncontrada.Comentarios.Replace("", "<br>").Replace("[", "<span style='color:grey'>[").Replace("]", "]</span>");
                _vista.Tarea = tareaEncontrada;
            }
        }
        public void OnLoad()
        {
            string urlReunion = null;
            if (_vista.Tarea != null && _vista.Tarea.ReunionAsignada != null)
                urlReunion = _vista.Tarea.ReunionAsignada.URL;
            SPUser usuarioActual = SPContext.Current.Web.CurrentUser;
            if (_vista.Tarea == null
                 (!_usuarioRepo.EsAdministrador(urlReunion, usuarioActual.LoginName)
                && !_miembroRepo.EsOrganizador(urlReunion, usuarioActual.LoginName)
                )
                )
            {
                if (_vista.Tarea != null && usuarioActual.LoginName == _vista.Tarea.Asignado)
                    _vista.HabilitarEdicionParcial();
                else
                    _vista.HabilitarControles = false;
                /// Esto es porque al deshabilitar el control se pierde el valor
                _vista.Asignado = _vista.Tarea != null ? _vista.Tarea.Asignado : "";
            }
        }








9. Si necesito presentar data sin importarme como la vista guarde el estado de la misma crearé en la interfaz de la vista una propiedad set y dejaré libertad al control de usuario como enlaza los datos al control ya que mi presentador no conoce nada sobre los controles definidos en mi control de usuario.

















image









image









Bueno amigos, en la segunda parte veremos el Modelo como interactúa con el Presentador y las Entidades viajan a través de los 3 sujetos Vista, Presentador y Modelo.









Los dejo con una ultima imagen parcial de la solución y referencias útiles para entender el patrón.









image Para efectos de simplicidad en el deployment no cree un proyecto por cada capa pero es tan sencillo con este diseño como crear los proyectos tipo librería y mover las clases a cada proyecto respectivo, si tenemos problema de referencia circular con los proyectos muy probablemente no delegamos correctamente las responsabilidades y/o no agrupamos el código debidamente en los proyectos.









Por el tipo de proyecto que es para crear un proyecto por cada capa en mi experiencia es necesario llevar un riguroso control de las versiones de los ensamblados para evitar que otros elementos web que utilizan los mismos ensamblados dejen de funcionar por el deployment de los nuevos lo cual se traduce en buen chapín “nos sale mas caro el caldo que los frijoles “, por lo que todo esta en un solo proyecto tipo solución de SharePoint para evitar estas inconveniencias en un ambiente productivo al momento de hacer el deployment de la solución.






En resumen vimos los conceptos y los beneficios que nos trae la aplicación de este patrón como un forma de hacer las cosas buscando una mecánica sistemática que nos ponga en una línea de producción imaginaria y obtengamos los beneficios de un código limpio que desacopla por responsabilidades los componentes haciendo mas fácil su mantenimiento, adaptación al cambio y finalmente porque no decirlo, “testeable “.






Hasta la próxima parte, Code4Fun!






Manolo Herrera









Artículos recomendados:













Arquitectura de la Interfaz de Usuario por Martin Fowler









Presentation Model por Martin Fowler









Passive View por Martin Fowler

martes, 6 de abril de 2010

Comportamiento curioso del control PeopleEditor de la familia SharePoint

Contexto:

Este control nos toda la funcionalidad de capturar los usuarios del Active Directory en nuestro elementos web personalizados tal y como lo hace SharePoint por lo que es muy útil y productivo.

Para los que no lo conocen este es un “screenshot” de como luce

image

Y en código HTML de un control de usuario luce así:

<SharePoint:PeopleEditor ID="CapturaAsignado" runat="server" IsValid="false" AllowEmpty="false"
                Height="20px" Width="400px" AllowTypeIn="true" MultiSelect="false" EnableViewState="true" />


Se debe declarar el ensamblado de los controles de SharePoint así:



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


Problema:



Bueno pero cual es el comportamiento curioso de este control; Dentro del código deshabilito el control dependiendo del usuario que este conectado y adivine qué? Pierde el valor que le fue asignado cuando se realiza un PostBack al servidor.  No así cuando siempre esta habilitado no sucede lo mismo.



Solución alterna:



Dentro de la lógica del código en el evento load() verificar si esta deshabilitado el control es decir CapturaAsignado.Enabled = false. Si es así sabemos que ya no lleva el valor debemos de asignarlo nuevamente al control (para ello debimos haberlo guardado antes obviamente).  Por ejemplo:




CapturaAsignado.CommaSeparatedAccounts = value;




Donde CapturaAsignado es el ID del control PeopleEditor y CommaSeparatedAccounts es su propiedad para asignar el login Name del usuario.



Espero evitarle un pequeño retraso en su trabajo.



Recuerde Code4Fun!,



Manolo Herrera