Directamente al grano
Al crear nuestro proyecto WPF, a simple vista nos encontramos con nuestro control XAML y asociado a este, nuestra conocida clase Code–Behind , con el que “handlearemos” los eventos de cada componente de nuestra UI. El ejemplo siguiente expone una aplicación sencilla WPF :
XAML
<Window x:Class="MiProyecto.MiVentana"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MiProyecto" Height="344" Width="355" >
<Grid>
<Button Name="but" BorderBrush="Azure">CLIC AQUI</Button>
</Grid>
</Window>
|
| |
ARCHIVO CODE BEHIND
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace MiProyecto
{
public partial class MiVentana : System.Windows.Window
{
public MiVentana()
{
InitializeComponent();
/// cool code, definimos al boton que al hacer clic delegue a
///un metodo (handler) la accion, pero para que definir un metodo
/// si lo podemos especificar ahi mismo
but.Click += delegate
{
MessageBox.Show("HOLA");
};
}
}
}
|
En el momento de ejecutar nuestro build de proyecto WPF, implícitamente el compilador está convirtiendo nuestro código XAML en BAML (Binary Application Markup Language), un archivo binario que representa nuestro código de marcas, manipulable directamente por nuestro Framework, y a la vez un archivo autogenerado ( G.CS) que contiene la implementación de nuestro Initialize Component y la definición de cada objeto.
Básicamente este método invoca directamente al LoadComponent de la clase System.Windows.Application. que se encarga de extraer el BAML del assembly, lo parsea y crea los controles, y eventos asociados.
//MiVentana.g.cs
using System;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MiProyecto {
public partial class MiVentana : System.Windows.Window, System.Windows.Markup.IComponentConnector {
internal System.Windows.Controls.Button but; //el boton
private bool _contentLoaded;
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
//Instanciamos un objeto de recursos como uri hacia nuestro archivo xaml.
System.Uri resourceLocater = new System.Uri(”/MiProyecto;component/MiVentana.xaml”, System.UriKind.Relative);
System.Windows.Application.LoadComponent(this, resourceLocater);
}
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(”Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {
switch (connectionId)
{
case 1:
this.but = ((System.Windows.Controls.Button)(target));
return;
}
this._contentLoaded = true;
}
}
}
|
¿Qué sucede cuando no podemos vincular nuestro Code-Behind con nuestro archivo auto generado G.CS?
Al momento de buildear nuestro proyecto WPF , obtenemos por ejemplo el error “The name 'InitializeComponent' does not exist in the current context”.
Esto se debe a que automáticamente el compilador reasigna al archivo G.CS el NameSpace del archivo code-behind con el que fue creado . Por ende estamos obligados a que el NameSpace de nuestro XAML, del code-behind y del G.CS coincidan.
Como solución inmediata podríamos renombrar los NameSpaces de las clases, al que tiene el ultimo archivo G.CS compilado. También podríamos buscar por file system nuestro archivo G.CS y renombrar su NameSpace, al que corresponda.
Está claro que si el XAML y su archivo asociado respetan esta igualdad, el G.CS se va a construir sin inconvenientes.
Debemos tener en cuenta que para el Visual Studio 2005, cada build que hagamos reconstruye el G.CS. En cierta forma lo podríamos considerar como un bug, ya que si modificamos el XAML y lo guardamos, nuestro archivo autogenerado no se entera y generara problemas para referenciarnos si no reconstruimos el proyecto.
Este detalle fue considerado en la nueva versión Orcas Beta 1, donde el archivo autogenerado se regenera cada vez que guardamos nuestro XAML.
METIENDO MANO EN EL G.CS
Cada objeto dentro del G.CS tiene un nivel de accesibilidad Internal, y esto no lo podemos modificar y aunque lo hagamos, cuando volvamos a buildear el proyecto, se volverán a asignar de la misma manera. Pero .Net nos brinda una ventaja… la clase Partial. Si en nuestro control WPF, queremos utilizar un objeto que no sea Internal, solo tendríamos que incluirlo en otra Partial Class con el mismo nombre y el nivel de accesibilidad que quisiéramos.
Podremos modificar directamente el G.CS, pero no es lo recomendable ya que el compilador se basa inicialmente en este archivo para reconstruir la UI y no en el XAML.
Bueno, esto fue todo por ahora.
Hasta pronto!,
Gato
Developer @ ID Corporate Solutions |