Obtaining data from a grandchild form to the father

7

I work in a Windows Forms application, C #, IoC ninject. As the question says, obtain data from a grandchild form to the father (from the father a child form is called and this calls another form) and from the latter the data is taken and passed to the father.

This is easy to solve using global variables, but it is bad programming practice.

What I could do is implement events under a Singleton pattern by following this link 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; }
}

Collect Data

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 CompleteEvent.PasarDosVariables event 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 the data is crushed.

    
asked by Pedro Ávila 15.04.2017 в 03:09
source

2 answers

2

I have managed to implement what you recommended to me @Jesus Angulo has worked for me and I put it as an answer I hope this is good because it gave me few arguments. I'm going to pass information from a child form to the parent.

Child form (frmBusqueda)

public FrmBusqueda(string title, EnumAsignacionTablas t)
        {
            _titulo = title;
            _table = t;
            CompleteEvent.Complete += CompleteEvent_Complete;
            InitializeComponent();
        }

    public FrmBusqueda(string title, EnumAsignacionTablas t, IMessageHub evenHub) : this(title, t)
    {
        _eventHub = evenHub;
    }

private void ObtenerId()
        {
            if (dgvBusqueda.Rows.Count > 0)
            {
                if (dgvBusqueda.CurrentRow != null)
                {
                    _idRow = Convert.ToInt32(dgvBusqueda.CurrentRow.Cells[0].Value);
                    _desRow = Convert.ToString(dgvBusqueda.CurrentRow.Cells[1].Value);
                }
                _eventHub.Publish(new ColorSelected {Codigo = _idRow, StrValor = _desRow});
            }
        }

Parent form (frmArticle)

private void btnBuscarColor_Click(object sender, EventArgs e)
        {
            var argNombreEntidad = new ConstructorArgument("title", StrColour.NameEntity);
            var argT = new ConstructorArgument("t", EnumAsignacionTablas.Colour);
            var frm = CompositionRoot.Resolve<FrmBusqueda>(argNombreEntidad, argT);  
        _eventHub.Subscribe<ColorSelected>(OnColorSelected); 
        frm.ShowDialog();
    }

    private void OnColorSelected(ColorSelected colorEvent)
    {
        if (colorEvent.Codigo != 0 && !string.IsNullOrEmpty(colorEvent.StrValor))
        {
            if (DetalleItemColour.Count != 1)
            {
                var entity = new Colour()
                {
                    ColourId = colorEvent.Codigo,
                    Nombre = colorEvent.StrValor
                };
                _detalleColour.Add(entity);
                dgvColor.AutoGenerateColumns = false;
                dgvColor.DataSource = DetalleItemColour;

                //De suscribir
                _eventHub.ClearSubscriptions();
            }
            else
            {
                MessageBoxEx.EnableGlass = false;
                MessageBoxEx.Show(this, "Solo se permite un solo Color", StrColour.NameEntity,
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                vBool = false;
                colorEvent.Codigo = 0;
                colorEvent.StrValor = String.Empty;
            }
        }
    }'

ColorSelected Class

public class ColorSelected
    {
        public int Codigo { get; set; }
        public string StrValor { get; set; }
    }

It works for me if there are any comments or corrections welcome.

    
answered by 29.05.2017 / 05:56
source
5

Probably what can help you is a better implementation of the Pub / Sub pattern, which, based on events, allows an uncoupled communication between components without a 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:

     public FrmMain(IMessageHub eventHub)
     {
        _eventHub = eventHub;
        //_eventHub.Subscribe<ColorSelected>(p => Console.WriteLine($"Id is: {p.Color}"));
        _eventHub.Subscribe<ColorSelected>(OnColorSelected);
     }

     private void OnColorSelected(ColorSelected colorEvent)
     {
         ...
         var entity = new Colour()
         {
             ColourId = colorEvent.Codigo,
             Nombre = colorEvent.StrValor
         };
         _detalleColour.Add(entity);
         dgvColor.AutoGenerateColumns = false;
         dgvColor.DataSource = DetalleItemColour;

        ...
        //algun evento para que el padre se entere
        _eventHub.Publish(new CompletedEvent());
     }

As you can see we have the possibility of launching a different infinity of events without having to define them, we only use a class as a contract for this event and we can subscribe and de-subscribe to them in order to communicate our application uncoupled.

  

The grandson launches an event class that the son listens to and the son launches an event that the father finally processes.

  

Finally, to use IMessageHub, we register the implementation in our IoC container (because using static classes, although easier, is considered a bad practice too).

kernel.Bind<IMessageHub>().ToConstant(MessageHub.Instance);
    
answered by 15.04.2017 в 07:13