viernes, 15 de febrero de 2008

Accediendo desde Webpart a los controles

Webparts es la propuesta Microsoft de bea-Portal, para hacer sitios.
bueno la mayor gracia de Webpart es que te da la funcionalidad de arrastrar los paneles por la pagina, y estas son permanentes en el tiempo. como el tiempo es poco y estoy por irme de vacaciones(yupi) en otra ocasion hablere mas del concepto, beneficios y contras de webparts.

Nacio de saber como podemos hacer para que webparts cambie un estado en un userControl o control de usuario para asi poder hacer una accion, dependiendo del valor.


primero en un WebpartsZone, arrastramos desde la parte derecha (solucion Explorer) nuestro UserControl (ojo que hablo de las que tienen extension ACSX).

a nuestro control le definimos un atributo y un property, para que webparts puedas modificar el atributo.

Este es el codigo en el aspx

<%@ Control Language="VB" AutoEventWireup="false" CodeFile="WebUserControl.ascx.vb" Inherits="WebUserControl" %>
<table>
<tr><td colspan="2">
<asp:Label ID="TituloLbl" runat="server" Text="Titulo"></asp:Label></td></tr>
<tr>
<td>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</td>
<td>
<asp:Button ID="Button1" runat="server" Text="Button" />
</td>
</tr>
</table>


Y en nuestro asp.vb tenemos lo siguiente:
Partial Class WebUserControl
Inherits System.Web.UI.UserControl
Private _Titulo As String = String.Empty
<WebBrowsable()> _
<Personalizable()> _
Public Property tutulo() As String
Get
Return Me._Titulo
End Get
Set(ByVal value As String)
Me._Titulo = value
Me.TituloLbl.Text = value

End Set
End Property
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
End Class


esta listo el primer paso. de esta forma webparts podra acceder al property de nuestro userControl, ojo que el WebBrowsable y Personalizable son super importantes si no estan webparts, no sera capaz de leer el property.

Si se fijas en SET, no solo cambia el valor de _Titulo, si no que tambien realiza la accion de cambiar el texto de un label.




Segundo paso

Tenemos que agregar un editorZone y dentro un PropertyGridEditorPart, este es el que es capaz de leer las propiedades de los controles y modificarlas.

A mi me quedo un codigo de este estilo.

<asp:EditorZone ID="EditorZone1" runat="server">
<ZoneTemplate>
<asp:PropertyGridEditorPart ID="PropertyGridEditorPart1" runat="server" />
</ZoneTemplate>
</asp:EditorZone>


Entonces cuando a webparts le digamos que se muestre en modo de edicion, nos mostrar un panel, donde podremos cambiar todos los varoles que queramos.

Importante
PropertyGridEditorPart solo lee property no lee atributos privados, solo property, ademas estos deben ser publicos.

Haciendo controles anidados


Muchas veces me he preguntado como hacen .Net para anidar los controles. en mis primeras experiencias al desarrollar mi primer control. me fue imposiblee realizar esto.

bueno lo que queremos lograr seria algo como esto:

<cc1:MyControl ID="server"   popUpID="panel1" Title="este es el titulo" >
<cc1:MyControlColumnas label="Nombre Persona" name="nombre" runat="server" Visible=true/>
<cc1:MyControlColumnas label="Edad Persona" name="edad" runat="server" Visible=true/>
</cc1:MyControl>




bueno por parte, como ya sabemos hacer nuestro control, ahora solo tenemos que hacer un una clase extienda de control Builder

  Public Class MyPortalBuilder : Inherits ControlBuilder
Public Overrides Function GetChildControlType( _
ByVal tagName As String, _
ByVal attributes As IDictionary) As Type
If tagName.ToLower() = "MyPortalColumna".ToLower Then
Return GetType(MyPortalColumna)
End If
Return Nothing
End Function
End Class



En este codigo sobre-escribimos el metodo GetChildControlType y le decimos que nos retorne el tipo de nuestro elemento que esperamos.


Pero eso no es todo en nuestra clase del control padre, tenemos que agregar esto.
ControlBuilder(GetType(MyPortalBuilder)), _
actualemten mi declaracion antes de mi clase es la siguiente:
 < _
ParseChildren(False), _
ControlBuilder(GetType(MyPortalBuilder)), _
ToolboxData("<{0}:MyPortal runat=""server"" ID='MyPortal1' >" + vbCrLf + _
"<{0}:MyPortalColumna runat=""server"">" + vbCrLf _
+ "<{0}:MyPortalPortlet runat=""server"" title=""Title"" contentId=""div1""/>" + vbCrLf _
+ "</{0}:MyPortalColumna>" + vbCrLf _
+ "</{0}:MyPortal> ")> _



Pero aun no termina esta tarea, parece tediosa y larga, pero la verdad es que en la practica no lo es tanto este es el ultimo paso.


Definimos una coleccion(en la clase padre) para guardar todos los hijos que esperamos, en mi caso yo utilice un arraylist. y tenemos que sobreescribir un metodo, para que llenemos nuestro Arraylist.

Protected Overrides Sub AddParsedSubObject(ByVal obj As Object)
If TypeOf (obj) Is MyPortalColumna Then
Me._columnas.Add(obj)
End If
End Sub


de esta forma ya tenemos nuestros controles ya listos.

IMPORTANTE

  • Nuestra clase hija tambien tiene que extender de webControl, si no esto no funcionara.

  • en el ultimo codigo(el metodo AddParsedSubObject) "_columnas" es mi attributo de la clase padre.




  • Conclusion

    con esto podemos hacer casi lo que se nos ocurra, podemos recorrer los hijos y leer valores desde ellos de forma trasparente. en mi caso realize una grilla, y dentro de ella tengo una coleccion de columnas, estas columnas le indican a la grilla que valores mostrar.

    jueves, 7 de febrero de 2008

    Activando Eventos con controles desarrollados

    Ya desarrollamos un pequeno control, pero ahora como hacemos para que este vaya al servidor, y ejecute una accion en este, es decir, cuando nosotro hacemos click sobre algo queremos que nuestro control vaya a realizar un metodo en el codebehind.


    Por ejemplo nosotros desarollamos en control llamado customerControl (button) y queremos darle la posibilidad a los desarrolladores que usen este control, de programar un evento, en este caso el evento click.

    manos a la obra.
    Namespace MyControl
    <ToolboxData("<{0}:testControl runat=""server"" ID='testControl1'/>")> _
    Public Class testControl : Inherits Control
    Implements IPostBackEventHandler
    Public Event Click As EventHandler

    Protected Overridable Sub OnClick(ByVal e As EventArgs)
    RaiseEvent Click(Me, e)
    End Sub

    Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements IPostBackEventHandler.RaisePostBackEvent
    OnClick(EventArgs.Empty)
    End Sub

    Protected Overrides Sub Render(ByVal output As HtmlTextWriter)
    output.Write(("<INPUT TYPE = submit name = " & Me.UniqueID & " Value = 'Click Me' />"))
    End Sub
    End Class
    End Namespace


    Implements IPostBackEventHandler
    nuestra clase de control tiene que ser implementada por esta clase, para que podamos capturar los eventos genrados en el cliente.

    Public Event Click As EventHandler
    con esta linea definimos el evento click de esta forma al hacer soble click sobre el objeto , nos aparerecera el metodo click, el encabezado de ese metodo seria algo asi.
    Protected Sub testControl1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles testControl1.Click

    Protected Overridable Sub OnClick(ByVal e As EventArgs)
    Definimos el metodo un sub (llamado por algunos), ojo que este metodo tiene que ser sobre-escribible(Overridable). esta funcion recibe en E todos los argumentos.

    RaiseEvent Click(Me, e)
    llamamos internamente al evento click, y le pasamos nuestro objeto, es decir, ME o THIS. y los argumentos que nos llegaron como parametros.

    Public Sub RaisePostBackEvent(ByVal eventArgument As String) Implements IPostBackEventHandler.RaisePostBackEvent
    basicamente es un Sub, que es implementado por IPostBackEventHandler.RaisePostBackEvent

    OnClick(EventArgs.Empty)
    llamamos al sub con argumentos vacios.



    En nuestro aspx, al momento de arrastrar el control se despliega lo siguiente:



    en mi caso en el aspx.vb deje lo siguiente:
    Protected Sub testControl1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles testControl1.Click
    MsgBox("este es un click desde un testControl")
    End Sub

    Desarrollando mi primer control en .NET

    Primero, que todo esta es la primera vez que estoy tratando de desarrollar un control en .NEt, esto al parecer es muy util, ya que muchas veces los controles de .NEt no satisfacen nuestras necesidades.


    Esta es la clase de mi primera clase.

    Namespace MyControl
    <ToolboxData("<{0}:testControl runat=""server"" ID='testControl1'/>")> _
    Public Class testControl : Inherits Control

    Protected Overrides Sub Render(ByVal output As HtmlTextWriter)
    output.Write(("<INPUT TYPE = ""text"" name = " & Me.UniqueID & " Value = '' />"))
    End Sub
    End Class
    End Namespace


    <ToolboxData("<{0}:testControl runat=""server"" ID='testControl1'/>")>
    Esta linea indica el texto que se escribira al momento que arrastremos desde el toolbox nuestro control hacia una pagina aspx.

    Public Class testControl : Inherits Control
    nuestra clase tiene que extender desde Control, para asi poder sobre-escribir los metodos, en este caso solo sobre-escribimos el metodo render

    Protected Overrides Sub Render(ByVal output As HtmlTextWriter)
    Sobre-escribimos el metodo render de la clase Control, la funcion de este metodo es basicamante renderizar o escribir en el cliente. es recibe un parametro de tipo "HtmlTextWriter". nosotros podemos agregarle texto a este objeto con "output.Write" este es muy parecido a un "stringBuilder"

    miércoles, 6 de febrero de 2008

    .NET AJAX Control Toolkit problema con javascript (Sys is not defined)

    Ultimante me encontre con un problema con esta libreria de .NET, pero el problema no era en desarrollo si no que en produccion, asi que era aun mas preocupante.

    El error es que al cliente le muestra un error de javascript, el cual dice que la variable "sys" no es definida.

    Causa:
    AjaxControlToolkit, ocupa recursos embedidos, es decir los controles contienen sus propios js, imagenes y css, lamentablemente estos no logran ser interpretados o procesados por servidor.

    Esta es la linea que agrega el control, para llamar a un javascript


    <script src="/WebSiteControl/WebResource.axd?d=Tm3Cyn9D......" type="text/javascript"></script>

    Solucion:
    como IIS, o el servidor de desarrollo, no logra interpretar la extensiones "axd"(esto es curioso, en mi caso estaban configurado para que los interpretara iisapi.dll) hay que agregar las siguientas lineas en el web.config.




    <httpHandlers>
    <remove verb="*" path="*.asmx" />
    <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory,System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" />
    <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory,System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" />
    <add verb="GET,HEAD" path="ScriptResource.axd"type="System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,PublicKeyToken=31bf3856ad364e35" validate="false" />
    </httpHandlers>

    Esto va dentro del tag "Web.config" de esta forma nuestro application Server sabra que hacer cuando se encuentre con una extension "axd"

    --
    Atte.
    Víctor Hugo Saavedra.
    http://vhspiceros.blogspot.com