Mostrar archivos de imagen en WPF utilizando enlace a datos.


Holal Qué tal.


Continuando con el ejemplo del post anterior (http://bit.ly/oh0m9k), referente al manejo de imágenes en WPF, ejemplificaremos el manejo de las imágenes de la misma manera pero, esta vez, utilizando enlace a datos y la clase Binding.


Antes, tenemos que hablar un poco de lo que es el enlace a datos con WPF. Trataré de ser breve y de no ahondar tanto para llegar más rápido a lo que nos ocupa.


El enlace a datos en objetos de la interfaz de usuario de WPF está determinado a través de la clase Binding, expuesta en la mayoría de las ocasiones, dentro del código de XAML definiendolo directamente en la asignación del valor de la propiedad que se quiere enlazar.


Debemos tener en cuenta que para realizar el enlace de datos, se debe contar con las condiciones necesarias para que esto sea posible, empezando por identificar las propiedades que podemos enlazar, las cuales deben ser propiedades de dependencia y que no sean de solo lectura. Otra consideración importante, es que las propiedades se enlazan a valores establecidos en objetos con la finalidad de mostrar los datos que contienen sus propiedades, en la interfaz de usuario.


Comúnmente se asignan los valores de los objetos directamente a las propiedades de los controles contenidos en la interfaz de usuario desde el código, teniendo complicaciones al momento de implementar la actualización de la información presentada en la interfaz de usuario de manera dinámica cuando los valores en las propiedades de nuestros objetos cambian durante la ejecución del código, derivando en la definición de más código que incluyen condiciones en la ejecución y eventos que pudieran estar de más con el uso del enlace a datos utilizando Binding.


La clase Binding ofrece mecanismos prácticos para que la información que se muestra al usuario sea la misma que contienen las propiedades de nuestros objetos.


Para iniciarnos en el uso de Binding debemos tener presente que, para que la información que contienen las propiedades de nuestros objetos se muestren correctamente en la interfaz de usuario utilizando enlace a datos en WPF y XAML, deben existir cuatro elementos necesarios para que funcione de la mejor manera. Primeramente debemos definir el Destino del enlace, el cual será un control de la interfaz de usuario, dicho de una mejor manera, un objeto de dependencia. Seguido de esto, identificaremos en el objeto de dependencia, la propiedad de dependencia que será la encargada de mostrar el dato. Con esto tenemos definido ya el destino, ahora bien, debemos identificar el objeto de origen, el cual expondrá  los datos y por último, la propiedad en este objeto que será la que proveerá el dato a la interfaz de usuario.


Con esto, hemos definido los cuatro elementos necesarios para realizar el enlace a datos utilizando Binding en WPF. En resumen, los cuatro elementos son un objeto de destino del enlace, una propiedad de destino del enlace, un objeto de origen del enlace y una propiedad de origen del enlace. Recordemos que la propiedad de destino de enlace debe ser una propiedad de dependencia.


Como podrán observar, la propiedad de origen de destino no es necesariamente una propiedad de dependencia y los objetos de origen de enlace no están restringidos a ser únicamente los personalizados, también, los propios elementos de la interfaz de usuario pueden ser objetos de origen de enlace. Como veremos en otra publicación en otra ocasión.


Para ejemplificar, dentro de nuestro ejemplo tenemos declarado un control Image denominado imgFoto, este control mostrará una imagen como dato enlazado. La declaración XAML será algo como esto:


<Image x:Name=”imgFoto” Width=”100″ Height=”100″ Margin=”5″


        Source=”{Binding Path=Image}” />


 


Podemos notar ciertas características en la definición del enlace a datos, primeramente veremos que la propiedad Source se declara como habitualmente se hace, sin embargo, dentro de la acotación definida por las comillas se agrega la declaración del enlace entre llaves ({}),  se pone la palabra Binding que hace referencia a la clase del mismo nombre y en seguida la asignación de Path con el nombre de la propiedad de origen del enlace, misma que está definida en el objeto de origen del enlace.


La clase Binding expone una propiedad denominada Path, esta propiedad es la que establece el enalce con la propiedad de origen. Es una propiedad predeterminada, a menos que se requiera la declaración explicita se podrá omitir, y lo que se escriba inmediatamente enseguida de Binding será tomado como el nombre de la propiedad de origen del enlace y será asignado a la propiedad Path. Teniendo en cuenta esto, la declaración puede quedar como sigue:


<Image x:Name=”imgFoto” Width=”100″ Height=”100″ Margin=”5″


        Source=”{Binding Image}” />


 


De este modo el código de nuestra ventana quedará conformado de manera inicial como lo siguiente:


<Window x:Class=”EjemplosWPF.MainWindow”


        xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”


        xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”


        Title=”MainWindow” Height=”350″ Width=”525″>


    <Grid>


        <StackPanel HorizontalAlignment=”Center” VerticalAlignment=”Center”>


            <Image x:Name=”imgFoto” Width=”100″ Height=”100″ Margin=”5″


                    Source=”{Binding Image}” />


            <Button x:Name=”btnFoto” Width=”100″ Height=”25″


                    Content=”Agregar Foto” Margin=”5″ Click=”btnFoto_Click”/>


        </StackPanel>


    </Grid>


</Window>


 


Debemos declarar ahora la clase que define al objeto de origen del enlace, será una clase simple y estará definida como sigue:


public class Foto


{


    BitmapImage image;


    public Foto()


    {


        image = null;


    }


 


    public BitmapImage Image


    {


        get


        {


            return image;


 


        }


        set


        {


            image = value;


       }


 


    }


}


 


Para efectos del ejemplo, esta clase la pueden crear enseguida de la clase de la ventana, dentro del mismo Namespace.


En la ventana, el código quedaría de la siguiente manera:


public partial class MainWindow : Window


{


    Foto foto;


    public MainWindow()


    {


        InitializeComponent();


        foto = new Foto();


        DataContext = foto;


    }


 


    private void btnFoto_Click(object sender, RoutedEventArgs e)


    {           


        if (foto.Image == null)


        {


            OpenFileDialog openFile = new OpenFileDialog();


            BitmapImage b = new BitmapImage();


            openFile.Title = “Seleccione la Imagen a Mostrar”;


            openFile.Filter = “Todos(*.*)|*.*|Imagenes|*.jpg;*.gif;*.png;*.bmp”;


            if (openFile.ShowDialog() == true)


            {


                if (new FileInfo(openFile.FileName).Length > 131072)


                {


                    MessageBox.Show(


                        “El tamaño máximo permitido de la imagen es de 128 KB”,


                        “Mensaje de Sistema”,


                    MessageBoxButton.OK,


                    MessageBoxImage.Warning,


                    MessageBoxResult.OK);


                    return;


                }


 


                b.BeginInit();


                b.UriSource = new Uri(openFile.FileName);


                b.EndInit();


                imgFoto.Stretch = Stretch.Fill;


                foto.Image = b;


 


                btnFoto.Content = “Quitar Foto”;


            }


        }


        else


        {


            foto.Image = null;


            btnFoto.Content = “Agregar Foto”;


        }


           


    }


}


 


Como podemos observar, no es muy diferente al código del ejemplo anterior, sin embargo podemos recalcar algunos cambios sustanciales.


Primero, se ha incluido la declaración de la variable foto, que es del tipo Foto, mismo que está definido por la clase que se muestra más arriba.


Segundo, en el constructor de la clase de la ventana, se agregó la instancia de la variable foto y se asigna la propiedad DataContext de la misma ventana. Aquí quiero hacer un paréntesis y hacer una observación sobre DataContext. Al asignar el objeto foto como DataContext del formulario, hará que en todas las declaraciones de Binding se asuma que los valores de Path son propiedades de origen de enlace contenidas en el objeto foto. Si existieran más controles con la definición de Binding, además del control imgFoto, los valores asignados a las propiedades Path de estos, estarían en el entendido de ser propiedades de origen de enlace definidas en el objeto foto. Si por el contrario, se asignara directamente a la propiedad DataContext del control imgFoto, solo se aplicarían los enlaces de datos a este control en exclusivo. Veremos un ejemplo de esto en la siguiente publicación.


Tercero; las validaciones cambiaron, de validar la propiedad Source del control imgFoto a validar la propiedad Image del objeto foto.


Cuarto; ahora en vez de asignar la propiedad Source del control imgFoto, se asigna la propiedad Image del objeto foto, que será la propiedad de origen del enlace, como podemos ver en el código XAML, la propiedad Source del control imgFoto está asignada con un Binding cuya propiedad Path, es la propiedad Image del objeto foto, de esta manera por ser del mismo tipo de valor que recibe la propiedad Source, se debe mostrar al momento en el control imgFoto.


Quinto; ahora se anula la propiedad Image del objeto foto en lugar de anular la propiedad Source del control imgFoto, que tendrá el mismo comportamiento que en el punto cuarto, quitando la imagen del control imgFoto.


Pues bien, aclarando esto, construimos el proyecto y ejecutamos… y… después de ver que al agregar la foto, no se muestra… nos desesperamos y caemos en la cuenta de que el Binding no sirve para nada… No, no es ninguna falla. El Binding para que sea dinámico debe estar notificado por un desencadenador (trigger), que actualizará la interfaz de usuario al momento en que cambia la propiedad. Para lograr esto debemos modificar un poco el código, solo en la clase Foto y en el XAML de la ventana, el código de la ventana se queda como está.


En la declaración de XAML, tenemos lo siguiente:


<Image x:Name=”imgFoto” Width=”100″ Height=”100″ Margin=”5″


        Source=”{Binding Image}” />


 


Debemos modificar esta declaración incluyendo la propiedad UpdateSourceTrigger asignándola con el valor PropertyChanged. Quedando como sigue:


<Image x:Name=”imgFoto” Width=”100″ Height=”100″ Margin=”5″


        Source=”{Binding Image, UpdateSourceTrigger=PropertyChanged}” />


 


Podemos observar que la propiedad se define explícitamente a diferencia de la propiedad Path, que ya habíamos comentado, y también vemos que las propiedades de Binding se incluyen en la declaración separadas por comas. Pero aun así, no es suficiente, ya que el valor PropertyChanged hace alusión a un evento que se desencadena en el objeto de origen del enlace, y debe incluirse en este como una implementación de la interfaz INotifyPropertyChanged que es parte del namespace System.ComponentModel. Así que haremos las modificaciones correspondientes. Primeramente al inicio de nuestro archivo de clase incluimos la declaración:


using System.ComponentModel;


 


Una vez incluida esta declaración, modificaremos la clase Foto para que quede de la siguiente manera:


public class Foto : INotifyPropertyChanged


{


    BitmapImage image;


    public Foto()


    {


        image = null;


    }


 


    public BitmapImage Image


    {


        get


        {


            return image;


 


        }


        set


        {


            image = value;


            PropertyChanged(this,


                new PropertyChangedEventArgs(“Image”));


        }


 


    }


 


    public event PropertyChangedEventHandler PropertyChanged;


}


 


Podemos observar que incluimos en la declaración de la clase las adecuaciones para implementar la interfaz INotifyPropertyChanged, además, se declara el evento PropertyChanged que de manera implícita implementa el miembro PropertyChanged de la interfaz INotifyPropertyChanged. Ahora bien, en la propiedad Image de la clase, en el descriptor de acceso set se lanza el evento PropertyChanged, como parte de los argumentos del evento se incluye como parámetro el nombre de la propiedad como un string. Así, toda vez que se asigne un valor a la propiedad Image del objeto foto,  se lanzará el evento PropertyChanged e informará del cambio del valor de la propiedad a Binding para que el contenido de las propiedades enlazadas se actualicen.


Ahora sí, hechas las modificaciones pertinentes, ejecutemos el código para ver complacientes que todo funciona como se esperaba que lo hiciera.


Este ejemplo es un adelante a lo que sigue, que es cómo manejar las imágenes como datos que pueden salvarse como parte de un registro en una base de datos. El próximo articulo estará dirigido a esto en el que incluiré todo lo necesario para manejar la imagen con bases de datos.


Espero que este artículo sea de utilidad y nos vemos en la próxima.


Octavio Telis.

One thought on “Mostrar archivos de imagen en WPF utilizando enlace a datos.”

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>