I work on a Windows Forms, C#, IoC ninject application. As the question says, get data from a grandchild form to the parent (from the parent a child form is called and this calls another form) and from the latter the data is taken and passed to the parent.
This is easy to solve using global variables, but it is bad programming practice.
What I was able to do is implement events under a Singleton pattern following this link to pass data between forms
Events
public static class CompleteEvent
{
public delegate void CompleteHandler(CompleteEventArgs arg);
public static event CompleteHandler Complete;
public static event CompleteHandler PasarDosVariables;
public static void RaiseEvent() { }
public static void RaiseEvent(string strValor)
{
//if (Complete != null)
// Complete(new CompleteEventArgs());
Complete?.Invoke(new CompleteEventArgs(strValor));
}
public static void RaiseEvent(int codigo, string valor)
{
PasarDosVariables?.Invoke(new CompleteEventArgs(codigo, valor));
}
}
public class CompleteEventArgs : EventArgs
{
public CompleteEventArgs() { }
public CompleteEventArgs(string strValor)
{
StrValor = strValor;
}
public CompleteEventArgs(int codigo, string valor)
{
this.Codigo = codigo;
this.StrValor = valor;
}
public int Codigo { get; set; }
public string StrValor { get; set; }
}
CollectData
public class RecolectarDatos
{
private static RecolectarDatos _datos;
private RecolectarDatos()
{
}
public static RecolectarDatos Instance()
{
//if (_controles == null)
// _controles = new ActivarControles();
//return _controles;
return _datos ?? (_datos = new RecolectarDatos());
}
public int Codigo { get; set; }
public string StrValor { get; set; }
}
My code that gives me problems when I use the event CompleteEvent.PasarDosVariables
more than once.
private void btnBuscarColor_Click(object sender, EventArgs e)
{
var argNombreEntidad = new ConstructorArgument("nombreEntidad", StrColour.NameEntity);
var argT = new ConstructorArgument("t", EnumAsignacionTablas.Colour);
var frm = CompositionRoot.Resolve<FrmInputBox>(argNombreEntidad, argT);
CompleteEvent.PasarDosVariables -= CompleteEvent_PasarDosVariables;
CompleteEvent.PasarDosVariables += CompleteEvent_PasarDosVariables;
frm.ShowDialog();
}
private void CompleteEvent_PasarDosVariables(CompleteEventArgs arg)
{
try
{
if (vBool)
{
if (arg.Codigo != 0 && !string.IsNullOrEmpty(arg.StrValor))
{
if (DetalleItemColour.Count != 1)
{
var entity = new Colour()
{
ColourId = arg.Codigo,
Nombre = arg.StrValor
};
_detalleColour.Add(entity);
dgvColor.AutoGenerateColumns = false;
dgvColor.DataSource = DetalleItemColour;
CompleteEvent.RaiseEvent();
arg.Codigo = 0;
arg.StrValor = String.Empty;
}
else
{
MessageBoxEx.EnableGlass = false;
MessageBoxEx.Show(this, "Solo se permite un solo Color", StrColour.NameEntity,
MessageBoxButtons.OK, MessageBoxIcon.Information);
vBool = false;
arg.Codigo = 0;
arg.StrValor = String.Empty;
}
}
}
}
catch (Exception e)
{
MessageBoxEx.Show(this, $"Error:{e.Message}", "Error Inesperado", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private void txtMarca_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F3)
{
var argNombreEntidad = new ConstructorArgument("nombreEntidad", StrMarca.NameEntity);
var argT = new ConstructorArgument("t", EnumAsignacionTablas.Marca);
var frm = CompositionRoot.Resolve<FrmInputBox>(argNombreEntidad, argT);
CompleteEvent.PasarDosVariables -= CompleteEvent_PasarDosVariables1;
CompleteEvent.PasarDosVariables += CompleteEvent_PasarDosVariables1;
frm.ShowDialog();
}
}
private void CompleteEvent_PasarDosVariables1(CompleteEventArgs arg)
{
if (arg.Codigo != 0 && !string.IsNullOrEmpty(arg.StrValor))
{
txtMarcaId.Text = Convert.ToString(arg.Codigo);
txtMarca.Text = arg.StrValor;
CompleteEvent.RaiseEvent();
arg.Codigo = 0;
arg.StrValor = string.Empty;
}
}
The problem is that when I use an event, the other event is activated and messes up the data.
Probably what can help you is a better implementation of the Pub/Sub pattern, which precisely, based on events, allows a decoupled communication between components without direct relationship in our application.
Implement the EventAggregator pattern
Using Easy.MessageHub we can create subscriptions to events within our application.
In the constructor of our form we subscribe to the events we need:
As you can see we have the possibility of launching an infinity of different events without having to define them, we only use a class as a contract for said event and we can subscribe and unsubscribe from them to communicate in a decoupled way with our application.
I have managed to implement what @Jesus Angulo recommended, it has worked for me and I put it as an answer, I hope the use is good since it gave me few arguments. I am going to pass information from a child form to the parent.
Child Form(frmSearch)
Parent form(frmArticle)
ColorSelected class
It is working for me if there is any comment or correction they are welcome.