Una vez que podemos pasar datos entre formularios como en la entrada Mensajería únicaWPF nos lo pone mucho más fácil y con mucho menos código.
Lo primero de todo debemos enlazar los controles con los datos de la clase y para ello debemos tener algún conocimiento de XAML y WPF (no es el fin de este artículo enseñar WPF)
Para llevar a cabo el paso de mensajes entre formularios mediante XAML, he creado una nueva ventana con un control Grid con tres columnas y tres filas, un control TextBlock y un control ProgressBar.
Las propiedades de los controles se enlazan con datos, estos datos proceden de una clase de negocio y esta clase es Message.
En WPF, para instanciar una clase, debemos hacerlo desde los recursos de la página o de un control, dependiendo del ámbito que se pretenda abarcar. En este caso, yo declaro la clase Message en los recursos del objeto Grid.
Una vez declarada, se creará una instancia de Message en cada nueva ventana y los controles se enlazan a la clase con Bindng en la propiedad del control que pretendemos enlazar y haciendo referencia a la propiedad de la clase Message. He incluido un conversor en la propiedad Visibility del control ProgressBar para convertir valores booleanos en valores de la enumeración Visibility como Visible, Hidden o Collapse; si es true, Visible y si es False, Collapse. En este caso hacemos los mismo, que es declarar la clase ConvertBoolToVisible (la cual implementa la interfaz IValueConverter) con una key llamada btv.
He hecho un binding sobre la propiedad Text del TextBlock a la propiedad infoText de la clase Message, la propiedad Value del control ProgressBar con la propiedad progress de Message y por último la propiedad Visibility con progressIsVisible ya su vez con el conversor btv.
<Window x:Class="WpfApplication1.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApplication1" mc:Ignorable="d" Title="Window2" Height="300" Width="300">
<Grid x:Name="grid" DataContext="message">
<Grid.Resources>
<local:ConvertBoolToVisible x:Key="btv"/>
<local:Message x:Key="message"/>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="100*"/>
<RowDefinition Height="100*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*"/>
<ColumnDefinition Width="100*"/>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tb" Text="{Binding infoText}" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<ProgressBar x:Name="pb" Minimum="0" Maximum="100" Value="{Binding progress}" Visibility="{Binding Path=progressIsVisible, Converter={StaticResource btv}}" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3" HorizontalAlignment="Center" Width="150" Margin="71,0,71,65"/>
</Grid>
</Window>
Y el código (code-behind)? Muchísmo más reducido, ya que en este caso solo existe un objeto Message de clase, asignamos dinámicamente el DataContext del control Grid (que será desde donde se alimenten los controles) y añadimos el evento CollectionChanged.
Para este caso, he efectuado dos cambios en la clase Message:
- Creación de un nuevo método público llamado
Cloneen la claseMessageque copia las propiedades de un objetoMessageal mismo objeto. - Implementación de la interfaz
INotifyPropertyChangedpor la claseMessagede modo que debe implementar el métodoOnPropertyChangedpara que la ventana detecte los cambios en las propiedades y pueda asignar los valores. - Creación del método
OnPropertyChanged("propertyName")el cual llamará al eventothis.PropertyChanged(this, new PropertyChangedEventArgs(p_PropertyName)); - Modificación en el set de las propiedades, incluyendo la llamada al método
OnPropertyChanged("propertyName").
Cada vez que se añada un nuevo mensaje, se clonará el objeto mensaje con los nuevos datos y se visualizarán en pantalla efectuando el mismo resultado que conseguimos mediante código, pero esta vez con menos código.
Clase Message modificada
using System;
using System.ComponentModel;
namespace WpfApplication1
{
public class Message: INotifyPropertyChanged
{
#region Constructor
public Message()
{
this.infoText = ""
this.progress = 0;
this.progressIsVisible = false;
}
public Message(string _text, bool _isVisible, int _progress)
{
setMessage(_text, _isVisible, _progress);
}
#endregion
#region Properties
private string _infotext;
private int _progress;
public int progress
{
get { return _progress; }
set
{
_progress = value;
OnPropertyChanged("progress");
}
}
public string infoText
{
get { return _infotext; }
set
{
_infotext = value;
OnPropertyChanged("infoText");
}
}
private bool _progressIsVisible;
public bool progressIsVisible
{
get { return _progressIsVisible; }
set
{
_progressIsVisible = value;
OnPropertyChanged("progressIsVisible");
}
}
public string infoText2 { get; set; }
#endregion
#region Events
public event EventHandler<EventArgsMessage> ChangedTextEventHandler;
public event EventHandler<EventArgsProgress> ChangedProgressEventHandler;
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String p_PropertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(p_PropertyName));
}
}
#endregion
#region Private Methods
void OnChangedText(EventArgsMessage e)
{
if (ChangedTextEventHandler!=null)
{
ChangedTextEventHandler(this, e);
}
}
void OnChangedProgress(EventArgsProgress e)
{
if (ChangedProgressEventHandler!=null)
{
ChangedProgressEventHandler(this, e);
}
}
#endregion
#region Public Methods
///
<summary>
/// Asigna los valores al mensaje
/// </summary>
/// <param name="_text">Texto del mensaje
/// <param name="_isVisible">Visibilidad del mensaje
/// <param name="_progress">Progreso
public void setMessage(string _text, bool _isVisible, int _progress)
{
this.infoText = _text;
this.progressIsVisible = _isVisible;
this.progress = _progress;
}
///
<summary>
/// Borra los valores del mensaje
/// </summary>
public void Clear()
{
setMessage("", false, 0);
}
///
<summary>
/// Efectua una copia de las propiedades de un mensaje
/// </summary>
/// <param name="message">Objeto a clonar
public void Clone(Message message)
{
this.infoText = message.infoText;
this.infoText2 = message.infoText2;
this.progressIsVisible = message.progressIsVisible;
this.progress = message.progress;
}
#endregion
}
public class EventArgsMessage:EventArgs
{
public EventArgsMessage() { }
public EventArgsMessage (string _oldText, string _newText)
{
this.oldText = oldText;
this.newText = _newText;
}
public string oldText { get; set; }
public string newText { get; set; }
}
public class EventArgsProgress : EventArgs
{
public EventArgsProgress() { }
public EventArgsProgress(int _newValue)
{
this.newValue = _newValue;
}
public int newValue { get; set; }
}
}
Code-Behind de la ventana
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
App.messages.CollectionChanged += Messages_CollectionChanged;
this.grid.DataContext = m;
}
Message m = new Message();
private void Messages_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
m.Clone((Message)item);
}
}
}
}
He aquí una muestra
Pues esto es todo. Estoy a vuestra disposición para cualquier duda.
Un saludo

















