Archivo

Archive for the ‘Tips y trucos’ Category

Cómo abrir un formulario y cerrar el padre en VB.NET


Casi nunca escribo cosas de VB.NET, puesto que mi lenguaje preferido en .NET es C#. Sin embargo, hoy surgió una discusión en los foros de MSDN, y creo que es algo recurrente, así que mejor hago esta pequeña entrada.

El asunto es el siguiente. Supongamos que tengo Form1 y Form2, dos formas. Al iniciar la aplicación, inicio Form1 y quiero que al hacer clic a un botón dentro de ésta, me abra Form2.

La primera aproximacion es hacer un ShowDialog:

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) _
        Handles Button1.Click

        Dim form As New Form2

        form.ShowDialog(Me)
        
    End Sub
End Class

Esto muestra la segunda forma como modal de la primera. Si quisiéramos cerrar la forma original (i.e. Form1) podríamos hacer un close:

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) _
        Handles Button1.Click

        Dim form As New Form2

        form.ShowDialog(Me)
        Me.Close()
        
    End Sub
End Class

Pero no nos sirve, porque Close no se ejecutará hasta que ShowDialog termine, es decir, hastas que Form2 se cierre. Lo que podemos hacer es invocar a Show, en lugar de a ShowDialog.

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) _
        Handles Button1.Click

        Dim form As New Form2

        form.Show()
        Me.Close()
        
    End Sub
End Class

Así, Close se ejecuta inmediatamente después de Show. Sin embargo, si haces esto ahora nos damos cuenta que al hacer clic en el botón, sí se abre momentáneamente el Form2, pero ¡se cierra la aplicación!

Había escuchado muchos argumentos de que esto era por diseño, que la forma inicial siempre debía estar corriendo, etc. Me puse a picarle al código y encontré que en las propiedades del proyecto es posible especificar la forma en la que una aplicación VB termina: si queremos que termine cuando se cierra el formulario principal o si queremos que termine cuando se cierre el último formulario.

image

Una vez que cambiamos la opción a “Cerrar cuando se cierre el último formulario” ¡el código anterior funciona a la perfección!

Tras bambalinas pude ver que el diseñador de VB.NET 2010 genera una clase llamada MyApplication, la cual tiene una propiedad: ShutdownStyle, de tipo ShutdownMode, así que las propiedades del proyecto seguramente sólo cambian ese valor.

Y dado que la documentación data de .NET Framework 2.0, supongo que esta funcionalidad está disponible desde entonces (circa 2005).

Así que ya sabes: ¡haz la prueba y deja tus comentarios!

Anuncios

Determinar si un usuario es dueño, miembro o visitante del sitio


Hace algunas lunas estábamos platicando sobre usuarios en SharePoint y y grupos de usuarios. Por un lado vimos cómo identificar si un usuario pertenece a un grupo determinado o no. Y unos días después vimos una forma sencilla para determinar si el usuario autenticado pertenece o no a un grupo de SharePoint en particular. .

Continuando con esta línea, me gustaría ahora platicar sobre tres grupos que, por defecto, tienen todos los sitios que creamos en SharePoint. Estos son:

1.- Dueños del sitio (Site Owners)

2.- Miembros del sitio (Site Members)

3.- Visitantes (Site Visitors).

Por defecto, los dueños del sitio tendrán permisos en la totalidad del sitio, y podrán crear contenido, páginas, añadir usuarios a otros grupos, crear y eliminar bibliotecas, etc. Por su parte, los miembros del sitio pueden añadir y eliminar documentos, configurar alertas para sí mismos y, en suma, añadir y eliminar contenido de las bibliotecas y listas personalizadas. Por último, los visitantes sólo podrán leer el contenido del sitio, nunca modificarlo.

Por supuesto, uno puede crear más grupos, cambiar los roles de los existentes o eliminarlos. Sin embargo, los tres antes mencionados revisten una importancia particular para nosotros como programadores: los tres grupos están mapeados en propiedades del objeto SPWeb.

En efecto, SPWeb tiene tres propiedades: AssociatedOwnerGroup, AssociatedMemberGroup y AssociatedVisitorGroup, las tres de tipo SPGroup, y hacen referencia al grupo de dueños, miembros y visitantes del sitio, respectivamente. Por supuesto, si borras los sitios por defecto, o los cambias, las tres propiedades regresarán null.

image

Esto abre nuevas posibilidades, respecto a lo que veíamos en los puestos anteriores. Por ejemplo, ahora determinar si el usuario actualmente autenticado es administrador, dueño del sitio o visitante es tan sencillo como esto:

SPWeb web = SPContext.Current.Web;
if (web.CurrentUser.IsSiteAdmin) {
    // el usuario es el administrador del sitio
} else if (web.AssociatedOwnerGroup.ContainsCurrentUser) {
    // el usuario es dueño del sitio, tiene acceso entero a todo...
} else if (web.AssociatedMemberGroup.ContainsCurrentUser) {
    // el usuario es miembro, puede añadir contenido a listas y documentos
} else if (web.AssociatedVisitorGroup.ContainsCurrentUser) {
    // el usuario es visitante, puede ver pero no modificar el contenido
} else {
    // el usuario está en algún otro grupo
}

Easy Peasy. Obvio querrás validar primero que las propiedades no sean nulas, pero bueno, es suficiente para ejemplificar.

Más información sobre grupos y seguridad en SharePoint 2010:Determine permission levels and groups.

Cómo buscar elementos en listas sin tener que usar CAML


Cuando hacemos desarrollo de componentes para SharePoint (WebParts, Application Pages, etc.) es muy común que tengamos que leer una lista (o biblioteca de documentos, galería de imágenes, etc.) para manipular suselementos. Puede ser, sin embargo, que queramos que la lectura se haga dependiendo de ciertos criterios. En otras palabras, queremos filtrar los elementos de la lista.

Hacer eso a mano (i.e. un foreach hacia SPList.Items) no suele ser una buena práctica, especialmente si nuestra lista contendrá muchos elementos. Naturalmente, la solución consiste en crearnos una consulta con CAML (Collaborative Application Markup Language, si la memoria no me falla) y buscar los elementos llamando a SPList.GetItems, como se muestra a continuación.

SPQuery query = new SPQuery();
query.Query = "[Mi consulta CAML]";

SPList list = SPContext.Current.Web.Lists["Mi Lista"];
SPListItemCollection items = list.GetItems(query);

// y hacer algo con items. 

Hacer consultas con CAML, sin embargo, es algo que lleva tiempo. El esquema de CAML para consultas tiene muchos elementos y la curva de aprendizaje es, en mi opinión, un tanto pronunciada. Por ello, muchas veces tenemos que usar herramientas como el U2U  CAML Query Builder para que nos ayude a generar la consulta.

Un truco que me ha dado resultado, y que incluso me da mucha más flexibilidad para poder configurar mi búsqueda posteriormente, consiste en crear una vista y programáticamente leer el CAML que ésta utiliza. Ya con el CAML, repetimos el paso del código anterior y listo.

Para lograr lo anterior, debemos a) obtener la lista sobre la que haremos la consulta, b) obtener la vista, usualmente por su nombre; c) obtener la consulta CAML de la vista a través de la propiedad Query, y d) con ese CAML crear un objeto SPQuery y ejecutar SPList.GetItems. Easy peasy:

SPList list = SPContext.Current.Web.Lists["Mi Lista"];
SPView view = list.Views["Mi vista"];
// alternativamente, si quieres usar la vista por defecto:
// SPView view = list.DefaultView;

SPQuery query = new SPQuery();
query.Query = view.Query;
// si analizas view.Query con el QuickWatch de Visual Studio
// pordrás ver el CAML de la vista...

SPListItemCollection items = list.GetItems(query);
// y hacer algo con los elementos encontrados. 

Este truco te permitirá, además, que el usuario (o administrador) de la lista modifique la vista en cuestión, sin tener que recompilar. Una buena técnica que últimamente me ha salvado trabajo de codificación y de estar lidiando con CAML…

Buscar los registros creados por el usuario actual


Cuando desarrollamos una solución utilizando SharePoint, al menos en mi experiencia, es común que nuestro cliente, en algún momento, nos haga el siguiente requerimiento: dada una lista o biblioteca determinada, mostrar sólamente los elementos que hayan sido creados por dicho usuario.

Hacer esto en SharePoint, por supuesto, no es problema alguno. Basta crear una vista, o modificar la vista por defecto, irnos a la sección de filtros y seleccionar el campo “Creado por”, es igual a, y en el valor, ponemos “[Yo]” (o “[Me]” en inglés).

Sin embargo, también es común que tengamos que aplicar la misma regla de negocio al momento de desarrollar nuestros componentes (por ejemplo, un WebPart con un SPGridView). Y para ello, ni modo de iterar sobre todos los elementos de una lista… mejor utilizar una consulta con CAML.

En particular, este es el CAML que nos interesa.

<Where>
    <Eq>
        <FieldRef Name="Author" />
        <Value Type="Integer">
            <UserID Type="Integer" />
        </Value>
    </Eq>
</Where>

El Where y el Eq no debe sorprendernos, son normalitos. La etiqueta FieldRef hace referencia al campo Author, que no es más que la columna de “Creado por”. Y en la etiqueta Value, hacemos dos cosas: primero, especificar que el campo será de tipo entero (naturalmente, puesto que se filtrará por el ID del usuario), y segundo, incluímos como etiqueta hija a UserID, también de tipo entero. La etiqueta UserId, por supuesto, hace referencia al usuario actualmente autenticado.

Luego entonces, el código para hacer realidad todo esto quedaría algo así:

SPQuery query = new SPQuery();
query.Query = @"<Where>
                                   <Eq>
                                       <FieldRef Name=""Author"" />
                                       <Value Type=""Integer"">
                                           <UserID Type=""Integer"" />
                                       </Value>
                                   </Eq>
                               </Where>";

SPList list = SPContext.Current.Web.Lists["Mi Lista"];
SPListItemCollection items = list.GetItems(query);

// y hacer lo que sea que hagamos con los elementos, 
// como llamar a GetData para obtener un DataTable
// y hacer un DataBind con un SPGridView... 

 

And be done with it…

Algunos recursos sobre FAST Search Server


Si usas SharePoint sabes que 2010 viene con FAST Search Server for SharePoint. Ésta es una herramienta poderosísima de búsqueda, tanto para sitios internos como externos y bases de datos.

Para programar contra FAST, haré una serie de artículos. Pero por el momento, revisa estos recursos.

1.- Consulta FAST Search Server desde aplicación cliente. Me sirvió mucho este tutorial, y en esencia lo que dice es que uses el servicio web Search.asmx provisto por SharePoint.

2.- FAST Query Language. FAST usa un lenguaje llamado FQL para realizar consultas personalizadas. Explora su contenido.

3.- Ejemplo Sencillo sobre FQL. Pues eso, un ejemplo sencillo.

Espero sirvan de introducción. Kudos al equipo de MSDN por esta documentación. También, si saben de más ejemplos, no duden en dejar el comentario, ya que es información difícil de localizar.

Tschüss!

Obtener la dirección del perfil de un usuario en SharePoint 2010


Un pequeño tip / código para obtener el perfil de un usuario en SharePoint 2010. Tienes que referenciar la librería Microsoft.Office.Server.UserProfiles para que funcione.

SPServiceContext context = SPServiceContext.GetContext(Web.Site);
UserProfileManager manager = new UserProfileManager(context);

string userLogin = "dominio\\usuario";
UserProfile profile;
if (!manager.UserExists(userLogin))
    profile = manager.CreateUserProfile(userLogin);
else
    profile = manager.GetUserProfile(userLogin);
url = profile.PersonalUrl.ToString();

En la línea 1 obtenemos un contexto de servicio, mientras que en la 2 obtenemos el administrador del perfil. En la sexta línea revisamos si existe el perfil del usuario, y si no existe la creamos. Si sí existe, obtenemos el perfil.

Por último, la propiedad PersonalUrl de UserProfile contiene un Uri hacia el perfil del usuario. Schön gut!

Apóyate en los metadatos de SharePoint


SharePoint tiene una herramienta peculiar para varios elementos, dentro del modelo de objetos. Muchos elementos tienen una propiedad a través de la cual es posible acceder a los metadatos de ese elemento. En particular, hay dos de éstos que son de mucha utilidad: SPWeb y SPListItem.

SPWeb tiene la propiedad AllProperties, mientras que SPListItem tiene la propiedad Properties. Ambas son de tipo Hashtable, así que es hora de desempolvar mi post sobre esa colección, si tienes dudas.

Ambas colecciones guardan metadatos, es decir, información adicional. SharePoint las guarda en la base de datos, como todo, y las carga al obtener el objeto dueño de los mismos. Esto los convierte en un perfecto lugar para guardar información relacionada o de configuración. Muchas veces esto es mejor que crear otras listas o guardarlas en el web.config.

La regla es así: si quieres guardar información a nivel del sitio, utiliza SPWeb.AllProperties. Por ejemplo:

SPContext.Current.Web.AllProperties.Add("Mi propiedad", "Mi valor");
SPContext.Current.Web.Update();
...
string value = SPContext.Current.Web.AllProperties["Mi propiedad"] as string;
Console.WriteLine(value); // imprime "Mi valor"

Para guardar información sobre un elemento de cualquier lista (incluyendo bibliotecas de documentos y galerías) usa SPListItem.Properties. Por ejemplo:

SPList list = SPContext.Current.Web.Lists["Mi lista"];
foreach (SPListItem item in list.Items)
{
    item.Properties.Add("Mi propiedad", "ID " + item.ID);
    item.Update();
}
...
foreach (SPListItem item in list.Items)
{
    string value = item.Properties["Mi propiedad"] as string;
    Console.WriteLine(value); // imprime "ID 1", etc
}

En general, es una buena idea usar SPWeb.AllProperties para cuestiones de configuración sobre el sitio (en lugar del web.config, por ejemplo) y usar SPListItem.Properties sobre información que no deberían ver los usuarios en la lista. Esto último, por ejemplo, es mejor que crear una columna en el SPList y ocultarla en las vistas.

Juega un rato con esto y verás qué tan útil resulta esto.