July 2008 - Artículos
Cuando se necesita cambiar el tema actual de un sitio web, teniendo en cuenta los temas disponibles localmente (tambien podemos tener temas globales pero eso es otro tema) o sea en el App_Theme deberiamos en un sector administrativo (el famoso sector privado) poder tener control de los temas (carpetas en App_Themes) para seleccionar y luego modificarlo permanentemente en el web.config
La idea…
Si tenemos un website de ejemplo con unos Themes (si lo quieres descargar al ejemplo click aqui)
Y en nuestro sector de administracion queremos algo asi
La demo consta de
Obtener Listado de Temas Locales a la aplicación web
Aqui solamente tendremos que listar los directorios en la carpeta App_Themes (para temas locales). Nos ayudamos con una funcion compartida (shared) o metodo de clase…
Public Shared Function TemasListado() As List(Of String)
Dim temas As New List(Of String)
'Enumerar
If (Directory.Exists(Current.Server.MapPath("~/App_Themes"))) Then
Dim subDirectorios() As String = Directory.GetDirectories(Current.Server.MapPath("~/App_Themes"))
For Each d As String In subDirectorios
Dim dirInfo As New DirectoryInfo(d)
temas.Add(dirInfo.Name)
Next
End If
Return temas
End Function
Tendriamos que pensar la estrategia cuando no tengamos temas disponibles.. esa parte lo dejo al lector :)
Para luego enlazarla al combo/dropdownlist:
ddlTemas.DataSource = TemasHelper.TemasListado
ddlTemas.DataBind()
ddlTemas.SelectedValue = TemasHelper.TemaActual
y ahora? como Obtener el tema actual?
Obtener Tema Actual
Aqui podremos consultar a la propiedad Page.Theme, pero como estas cambiando el tema al todo el sitio web (es la idea) tendriamos que obtener el valor desde el web.config. Nuevamente nos ayudamos por una clase helper para consultarla mas “comodamente”
Aqui obtenemos el archivo de configuracion web, la seccion de Pages (PagesSection)
Imports Microsoft.VisualBasic
Imports System.Web.Configuration
Imports System.IO
Imports System.Web.HttpContext
....
Public Shared Function TemaActual() As String
Dim webConfig As Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Dim seccion As PagesSection = CType(webConfig.GetSection("system.web/pages"), PagesSection)
Return seccion.Theme.ToString
End Function
Aqui el articulo de como leer/obtener propiedades de secciones del web.config nos puede ayudar
Guardar la modificacion del tema actual
Para guardar… algo parecido al obtener, pero aqui nos ayudamos por los metodos Save y SaveAs. En este caso particular tendremos que modificar con el metodo Save
Imports Microsoft.VisualBasic
Imports System.Web.Configuration
Imports System.IO
Imports System.Web.HttpContext
...
Public Shared Sub TemaCambiar(ByVal tema As String)
Dim webConfig As Configuration = WebConfigurationManager.OpenWebConfiguration("~") 'WebConfigurationManager.OpenWebConfiguration("/web.config")
Dim seccion As PagesSection = CType(webConfig.GetSection("system.web/pages"), PagesSection)
seccion.Theme = tema
webConfig.Save()
End Sub
NOTA 1: Temas Local y Tema Global ??
Aqui el ejemplo utilizo temas locales, tambien se puede configurar temas globales, es decir comunes para todos los sitios. Esto se realiza en la carpeta:
iisdefaultroot\aspnet_client\system_web\version\Themes
Nos podremos ayudar con la propiedad HttpRuntime.AspClientScriptVirtualPath
Aqui un articulo sobre el tema de Luis Ruiz Pavon
NOTA 2: Guardar tema en el profile del usuario, y asignar a la pagina actual
Un articulo como personalizar las paginas que nos puede orientar como guardar un tema en el profile del usuario
NOTA 3: Privilegios necesarios
(…from MSDN)Para abrir una sección en un archivo de configuración Web, la aplicación necesita permiso de Lectura para el archivo físico Web.config y para todos sus archivos principales en la jerarquía. Las aplicaciones de código administrado necesitan tener permiso para leer las secciones del sistema. Las aplicaciones de plena confianza y de gran confianza tienen estos permisos de forma predeterminada. En otras palabras, de forma predeterminada, las aplicaciones de media y baja confianza no podrán leer secciones de configuración.(…)
NOTA 4: Importante! Actualizacion del tema de la pagina para para la peticion actual (idem Nota 2)
Este cambio solamente lo utilizo en el sitio de administracion (fue la idea original), para luego ir al sitio ”Publico” y ver que el cambio se efectuo en el web.config.
No lo vamos a tener disponible hasta la proxima peticion de la pagina. Ya que el tema se enlaza a la pagina en el evento PreInit.
(…)La propiedad Theme debe establecerse antes del evento PreInit; si se establece la propiedad Theme después del evento PreInit, se producirá una excepción InvalidOperationException.(…)
Por eso en el ejemplo, si queremos visualizar el cambio tendriamos que volver a resfrescar…aqui nos ayudamos con un Redirect (pero es una tips simplemente)
Protected Sub btnCambiar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCambiar.Click
Dim temaNuevo As String = ddlTemas.SelectedValue
TemasHelper.TemaCambiar(temaNuevo)
'Para que tome el cambio algo un refresh de la pagina
Response.Redirect(Request.Path)
End Sub
Descargar Demo
Si no puedes ver la imagen de descarga click aqui
Enlaces
Por unas preguntas de los grupos de noticias de ASP.NET o de los foros de MSDN Latam, me dicidi a escribir la formas que tenemos de acceder desde codigo a propiedades/atributos de nuestras secciones en el web.config. Tambien un articulo que tenia en borrador de como modificar el tema del sitio del web.config
Empecemos por las clases que nos ayudan…
Tenemos por un lado el WebConfigurationManager, que como el nombre lo indica nos brinda manipular archivos de configuracion web. Debemos usar “preferentemente” esta clase para aplicaciones web, si quieres acceder a configuracion de aplicaciones winform/desktop utilizaremos ConfigurationManager.
Cuando necesitemos accesar en tiempo de diseño a la configuracion, por ejemplo creando webcontrol personalizados que cambien o modifican configuraciones de aplicacion utilizaremos WebConfigurationManager, idem cunado necesitamos aceder a configuracion de app de escritorio ConfigurationManager. Si el acceso lo realizamos en tiempo de ejecucion es indistinto.
Como obtener una seccion
Para este ejemplo utilizamos el acceso a la seccion pages bien simple solamente con el tema de las paginas
Aqui veremos
- OPCION 1: Metodo estáticos de la clase ConfigurationManager
- OPCION 2: Utilizando la clase WebConfigurationManager
- OPCION 3: Utilizando una instancia de la clase WebConfigurationManager con secciones especificas
- OPCION 4: Utilizando el metodo estatico (shared) GetWebApplicationSection de la clase WebConfigurationManager
Aqui estan…
- OPCION 1: Metodo estáticos de la clase ConfigurationManager
Aqui utilizamos GetSection (tambien tenemos disponible GetSectionGroup)
Ejemplo:
Dim seccion As ConfigurationSection = ConfigurationManager.GetSection("system.web/pages")
txtTemaActual.Text = seccion.ElementInformation.Properties("theme").Value
- OPCION 2: Utilizando la clase WebConfigurationManager
Aqui hacemos uso de la clase que nos recomienda .NET para manipular archivos web.config. Pero igualmente seguismos sin intellisense en las propiedades de la seccion
Ejemplo:
Dim webConfig As Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Dim seccion As ConfigurationSection = webConfig.GetSection("system.web/pages")
txtTemaActual = seccion.ElementInformation.Properties("theme").Value
- OPCION 3: Utilizando una instancia de la clase WebConfigurationManager con secciones especificas
Para tener un poco mas de “poder”
Ejemplo 1 (seccion pages):
Dim webConfig As Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Dim seccionPages As PagesSection = CType(webConfig.GetSection("system.web/pages"), PagesSection)
txtTemaActual.Text = seccionPages.Theme
Nota: si pueden apreciar que tenemos GET y SET para poder manipular esta propiedad… algo que necesitamos si queremos modificar el valor y volverlo a guardar/salvar
Tambien lo tendremos de la forma anterior
Ejemplo 2 (con la seccion sessionState):
Si tenemos la seccion
<web.config>
...
<sessionState
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
cookieless="false"
timeout="20" />
...
Para recuperar el Timeout…
Dim webConfig As Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Dim seccion As SessionStateSection = CType(webConfig.GetSection("system.web/sessionState"), SessionStateSection)
txtSessionStateTimeout.Text = seccion.Timeout
Pero lo tenemos todas las propiedades disponibles…
- OPCION 4: Utilizando el metodo estatico (shared) GetWebApplicationSection de la clase WebConfigurationManager
Aqui con menos codigo (que siempre es bueno) . No tendremos que enviar como parametro ninguna ubicacion como los anteriores. Sino simplemente toma el valor del archivo de configuracion de la aplicacion web actual
Dim seccion As PagesSection = WebConfigurationManager.GetWebApplicationSection("system.web/pages")
txtTemaActual.Text = seccion.Theme
Es recomendable castear al tipo que
Dim seccion As PagesSection = TryCast(WebConfigurationManager.GetWebApplicationSection("system.web/pages"), PagesSection)
Como guardar modificaciones de una seccion
Ya tenemos la seccion, podremos modificar pero para que el cambio sea efectivo y se persista en el web.config?
Nuestra clase de configuracion tiene dos metodos Save y SaveAs
Por ejemplo en nuestro caso de ejemplo:
Dim webConfig As Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Dim seccion As PagesSection = CType(webConfig.GetSection("system.web/pages"), PagesSection)
seccion.Theme = "Yoda"
webConfig.Save()
Aqui estamos ejemplificando con un propiedad en una seccion, mas detalle sobre esta tarea en este articulo:
NOTA: Secciones especificas AppSettings y ConnectionStrings
Existen “atajos” para secciones especificas (“archi-conocidas”) de nuestros archivos de configuracion como ser AppSettings y ConnectionStrings
Pero en definitiva son objetos AppSettingsSection y ConnectionStringsSection, que nos duevuelve directamente los que necesitamos.
En el caso de AppSettings nos devuelve la coleccion de NameValueCollection
En el caso de las cadenas de conexion nos devuelve la coleccion ConnectionStringSettingsCollection, sino tendriamos que hacer algo asi:
Para modificar si queremos hacer algo asi:
WebConfigurationManager.ConnectionStrings("EJEMPLOConn").ConnectionString = "NuevaCadena..."
Tendremos un error:
La configuración es de sólo lectura.
Detalles de la excepción: System.Configuration.ConfigurationErrorsException: La configuración es de sólo lectura.
para guardar la cadena de conexion modificada...
Dim webConfig As Configuration = WebConfigurationManager.OpenWebConfiguration("~")
Dim seccionConnString As ConnectionStringsSection = CType(webConfig.GetSection("connectionStrings"), ConnectionStringsSection)
seccionConnString.ConnectionStrings("EJEMPLOConn").ConnectionString = "NuevaCadena..."
webConfig.Save()
Enlaces:
Hace poco elBruno nos contaba sobre
Donde tienes documetacion sobre ASP.NET 3.5 SP1
Y recien me entero entrando de casualidad de esta documentacion
ASP.NET in .NET 3.5 SP1 Beta
http://www.asp.net/learn/3.5-SP1/
Donde podremos visualizar videos relativos a estos temas (por ahora)
- ASP.NET Dynamic Data
- ASP.NET MVC
- ASP.NET AJAX
- ADO.NET Data Services
- MVC Storefront Starter Kit
Mas enlaces…
Si necesitamos el listado de fuentes instaladas en el sistema en un dropdownlist/combobox solo debemos enlazarlo a la propiedad Drawing.FontFamily.Families.
Si necesitamos algo asi:
Podremos hacer un enlace a esta propiedad que retorna un array:
cboFuente.DataTextField = "Name"
cboFuente.DataValueField = "Name"
cboFuente.DataSource = Drawing.FontFamily.Families
cboFuente.DataBind()
(Aqui el databind es porque lo utilice en un ambiente web)
Enlaces
Huston… teniamos un problema! Va yo era el del problema. Con un amigo del trabajo Pedro (flamante programador Clipper!) teniamos que realizar acciones en un winform en un control Datagridview con un Checkbox. Simple no? Pero cuando queriamos acceder por codigo al valor de la columna DataGridViewCheckBoxColumn CellValueChanged no teniamos el cambio actual.
Problema
Tenemos una grilla con una columna DataGridViewCheckBoxColumn
Para que cuando tengamos evento click en el check…
LO PODAMOS DETECTAR !!! Pense que era mas facil de lo que crei, pero por eso aqui esta este instructivo con las dos opciones:
Antes que nada… explicación de porque no podemos hacer simplemente…con los eventos como las otras celdas:
Pero si lo hacemos en el evento CellContentClick, no tendremos actualizado el valor del check
Private Sub DataGridView1_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
MsgBox("Estado: " & Me.DataGridView1.Rows(e.RowIndex).Cells("check").Value)
End Sub
(from MSDN…)CellContentClick: Para los clicks en DataGridViewCheckBoxCell este evento se produce antes de que cambie el valor de la casilla de verificación(…)
Si lo hacemos aqui CellValueChanged (que es donde deberiamos consultar por naturaleza) solo se produce cuando el usuario deja la celda actual. Esto sucede porque los cambios no se plasman hasta luego de ejecutar el evento CellEndEdit.
OPCION 1: La parte “ortodoxa”… cambiar el estado por nosotros mismos. Tenemos el control
Aqui la idea es cambiar la propiedad de esta columna DataGridViewCheckBoxColumn a ReadOnly
Y en el evento CellContentClick, tendremos que ”artesanalmente” cambiar de estado… y alli si podremos recuperarlo.
Private Sub DataGridView1_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
If e.ColumnIndex = Me.DataGridView1.Columns.Item("check").Index Then
Dim chkCell As DataGridViewCheckBoxCell = Me.DataGridView1.Rows(e.RowIndex).Cells("check")
chkCell.Value = Not chkCell.Value
End If
MsgBox("Estado: " & EstadoCheck(e.RowIndex))
End Sub
(Nota: Aqui la columna checkbox se llama “check”, y el metodo EstadoCheck solo obtiene el estado del la columna con el check – para demo)
Entonces? Aqui es una forma ortodoxa de conseguir nuestro objetivo: “Tener un poco de control en el OnClick del checkbox en una columna DataGridViewCheckBoxColumn del Datagridview”
OPCION 2: Tener control del cambio en el CheckBoxColumn: Evento CurrentCellDirtyStateChanged (cuando se cambia el estado de alguna celda)
Esta opcion es la recomendacion de MSDN asi que, aqui va…
La columna checkbox (DataGridViewCheckBoxColumn) la dejamos como esta… sin propiedad ReanOnly seteada.
En el evento CurrentCellDirtyStateChanged preguntamos si la celda actual tiene cambios sin confirmar (propiedad IsCurrentCellDirty)
Private Sub DataGridView1_CurrentCellDirtyStateChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DataGridView1.CurrentCellDirtyStateChanged
If DataGridView1.IsCurrentCellDirty Then
DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
End If
End Sub
y alli si podremos consultar el valor… en el evento por naturaleza
Private Sub DataGridView1_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
MsgBox("Estado: " & EstadoCheck(e.RowIndex))
End Sub
Enlaces:
Nuevamente por una pregunta de grupo de noticias de ASP.NET, que también es común... de “Como deshabilitar del lado de cliente controles ASP.NET”
Esto es javascript así que uno tendría que incursionar en su lenguaje, como se instancia variables, búsqueda de controles y asignación de propiedades.
Dejo un ejemplo utilizando puro js y otro con una librería (framework javascript) que puede ser útil... UTIL (y es la recomendación)
La idea…
- Habilitado:
- Deshabilitado:
NOTA: Un pequeño retoque con estilos CSS para que cuando este deshabilitado el color de fondo sea gris.
<style type="text/css">
.disabled {
background-color: #C0C0C0; /*color: gris*/
}
</style>
OPCION 1: Clásica, puro js
Aqui vemos que tenemos un chekbox que lo recuperamos con el ID de cliente que tiene el webcontrol y dependiendo de eso lo deshabilitamos y cambiamos el estilo css
Para ocultarlo la propiedad es: visible y tambien display. Dejo abajo un enlace para que evalues cual de las dos necesitas (visible o display), pero la idea de ambos es que con una propiedad la ubicacion “fisica” utilizada por el control se mantiene y en otra se oculta completamente.
function EjemploCheck(){
var chk = document.getElementById('<%= chkNumeroManual.ClientId %>');
var txt = document.getElementById('<%= ExpeNumero.ClientId %>');
if (chk.checked==true) {
txt.disabled = false;
txt.className = '';
txt.focus();
}else{
txt.disabled = true;
txt.className = 'disabled';
}
Para utilizarlo en el evento onClick del chekbox tendrias que llamar a EjemploCheck, para el ejemplo1 utilice la funcion js llamanda “Ejemplo1”.
Por codigo asignamos el comportamiento.
Mis controles:
<asp:CheckBox ID="CheckBox1" runat="server" Text="Ejemplo 1" />
<asp:TextBox ID="TextBox1" runat="server" Enabled="false" CssClass="disabled"></asp:TextBox>
OPCION 1.1: Enviando controles como parametro de la funcion js
Se podria “generalizar” para tener un funcion js que no este sujeta a un control especifico.
La idea es enviarle como parametro los controles.
<script language="javascript" type="text/javascript">
function Ejemplo2(chk, txt){
if (chk.checked==true) {
txt.disabled = false;
txt.className = '';
txt.focus();
}else{
txt.disabled = true;
txt.className = 'disabled';
}
}
</script>
Asignamos el comportamiento de la funcion “Ejemplo2” al checkbox:
'Para ejemplo 2
CheckBox2.Attributes.Add("onClick", "Ejemplo2(this, " & TextBox2.ClientID & ");")
Los controles (idem al anterior)
<asp:CheckBox ID="CheckBox2" runat="server" Text="Ejemplo 2" />
<asp:TextBox ID="TextBox2" runat="server" Enabled="false" CssClass="disabled"></asp:TextBox>
OPCION 2: Utilizar librerias js: jQuery
Utilizando potentes y recomendable librerías de JavaScript, en esta oportunidad un ejemplo con jQuery
Este ejemplo hace lo mismo que el de arriba, pero sin necesidad de escribir nada mas... ni siquiera agregar el comportamiento por codigo al control (lo hacemos desde js)
(claro que necesitas descargar el script y asociarlo a tu pagina)
jQuery nos brinda mucha “asbtraccion” y tenemos mas simple algo que se nos hacia complejo manipular, por ejemplo los estilos CSS asociados a un control. Aqui con los metodos .addclass y .removeclass nos dan transparencia para la coleccion de clases css que puede poseer un control.
<script src="js/jquery-1.2.3.min.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
$(document).ready(function() {
var chkNumeroManual = '#'+'<%= CheckBox3.ClientID %>';
var txtNumero = '#'+'<%= TextBox3.ClientID %>';
$(chkNumeroManual).click(function() {
if($(chkNumeroManual).is(":checked")){
$(txtNumero).removeClass("disabled");
$(txtNumero).attr('disabled', false);
}else{
$(txtNumero).addClass("disabled");
$(txtNumero).attr('disabled', true);
}
});
});
</script>
Esta primera aproximación utilizamos el metodo .attr, pero podremos utilizar el metodo .disabled ya que el control acepta esta propiedad.
O sea:
Entonces la función js queda:
<script language="javascript" type="text/javascript">
$(document).ready(function() {
var chkNumeroManual = '#'+'<%= CheckBox3.ClientID %>';
var txtNumero = '#'+'<%= TextBox3.ClientID %>';
$(chkNumeroManual).click(function() {
if($(chkNumeroManual).is(":checked")){
$(txtNumero).removeClass("disabled");
//$(txtNumero).attr('disabled', false);
$(txtNumero).disabled = true;
}else{
$(txtNumero).addClass("disabled");
//$(txtNumero).attr('disabled', true);
$(txtNumero).disabled = false;
}
});
});
</script>
Descargar ejemplo:
WebSite_DeshabilitarWebControl_VS2008.zip
{si no puedes visualizar la descarga click aquí}
Espero que te sirva de ayuda o guia
Enlaces:
Tomandome 5 minutos de relax, y “googleando un poco” me tope con xRank, que es algo parecido a un "rankeador" de búsqueda. Solo que parece que por ahora solo rankea celebridades
(muy para el canal E!). Primeramente lo compare con Google Trends, pero no tiene la misma idea de base...o sea no existe comparacion.
Antes que nada esta pantalla...
Ingreso a Live Search xRank
http://search.live.com/xrank
y la layenda: "Lo sentimos, xRank no se admite en tu ubicación" :(
Asi que me decidi a "Mudarme virtualmente" para probar ;) (algo parecido me sucedio con SkyDrive), pero aquí fue mas fácil solo hay que cambiar en las opciones de xRank de búsqueda
Que es?
Copy & paste de la ayuda:
"(...)xRank keeps track of notable people and puts them in order for you. We count Live Search web searches for movie stars, musicians, and other famous people. Then, we compile our findings into an insightful ranking formula that tells you who the world is searching for most. The result is a cultural snapshot of who's hot and who's not! (...)"
Me gusto la parte de snapshot. Que para mis amigos que no son IT (y que por ahi leen mis post) es como una fotografía de datos en un determinado punto del tiempo.
Buscando U2
A ver probemos... busquemos algo de MUSICA con Mayúsculas ok? que no es otra cosa que U2
y Google Trends...?
http://www.google.com/trends
Y no tiene nada que ver con lo anterior, similar pero ataca algo mas global: La historia de una búsqueda especifica. Aquí podremos ver el ranking de búsquedas en el transcurso del tiempo, es decir podremos comparar la frecuencia con que se busco una palabra a lo largo del tiempo con otra.
Y como “postre” podemos ver las Noticias que existieron en los picos de búsqueda, por ejemplo en la busqueda mas abajo la comparacion de U2 y Madonna, con picos de U2 en ultima gira mundial.
Una sola frase: Que buen servicio de Google... Impresionante...
Algo mas ejemplificador: FIFA WORLD CUP :)
http://www.google.es/trends?q=FIFA+WORLD+CUP&ctab=0&geo=all&date=all&sort=0
La mayoría de las búsquedas fue en el meses del mundial.

Acabo de utilizar un backup de mis post escritos en Windows Live Writer, mi laptop estuvo en coma 4 por razones de virus :(
Encontré una utilidad que hace el trabajo duro por nosotros (copiar y resguardar carpetas especificas y registros)
Live Writer Backup Utility Version 2.0
Entonces es mas fácil la tarea...
http://scottisafooldev.spaces.live.com/blog/cns!FE151030F50B5B37!556.entry
Nos crea un archivo: (extensión .wlwbackup)
Tip & Trick 1: Contenido
Si queremos visualizar su "interior" podremos cambiarle la extensión .wlwbackup a .rar
Tip & Trick 2: MSI y también stand-alone (.zip)
MSI: (enlace)
ZIP:
http://www.scottisafool.co.uk/LiveWriterBackupSetup.zip
Tip & Trick 3: Restauración en Vista
Ya en nuevo sistema intento restaurar, con mensaje de que se eliminara
Y me doy cuenta que no tiene permiso para estas acciones...
Había que ejecutar como Admin
Y alli si...
Lo único que no configuro correctamente fue mis configuración de los blogs...?? Acabo de enviar un email para mejor explicación al autor ;)
Enlaces: