none
Como capturar el evento de final de edición de una celda en un datagridtextcolumn de un datagrid RRS feed

  • Pregunta

  • Hola

    Tengo un datagrid al que le paso por binding la propiedad llamada "Modelo" de una clase ViewModel y esta propiedad contiene una Lista de Entidades del Modelo en este caso una lista de entidades "Cuadrante", con lo cual cada fila del datagrid es una entidad "Cuadrante" y lo que se ve es una serie de valores correspondientes a una serie de días y al final un valor que es el total de los anteriores.

    El caso es que lo que necesito es que al editar una fila automáticamente se actualice el total, es decir, el ultimo valor, pero en primer lugar no logro capturar ningún evento donde puede ver el nuevo valor que tiene no solo la celda en el datagrid sino la entidad subyacente y el evento CellEditEnding no me vale por que en este evento la edición aún no se ha cometido y no veo el cambio en la entidad.

    No se si lo que pretendo se puede hacer pero en esas andamos

    Un saludo


    kintela @esekintela

    martes, 8 de julio de 2014 7:48

Respuestas

  • Hola

    Al final lo he conseguido de esta manera

    En el evento CellEditEnding del datagrid tengo esto

                DataGridCell cell = GetCell(e.Row, 35);
                cell.Content = vm.Modelo[e.Row.GetIndex()].TotalFila;

    por que en la columna 35 es donde van los Totales que los saco de la propiedad TotalFila del ViewModel enlazado al datagrid

    Luego tengo estas 2 funciones

     public DataGridCell GetCell(DataGridRow row, int column)
            {
                DataGridRow rowContainer = row;

                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);

                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    if (cell == null)
                    {
                        dg_Cuadrante.ScrollIntoView(rowContainer, dg_Cuadrante.Columns[column]);
                        cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    }
                    return cell;
                }
                return null;
            }

            public static T GetVisualChild<T>(Visual parent) where T : Visual
            {
                T child = default(T);
                int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < numVisuals; i++)
                {
                    Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
                    child = v as T;
                    if (child == null)
                    {
                        child = GetVisualChild<T>(v);
                    }
                    if (child != null)
                    {
                        break;
                    }
                }
                return child;
            }

    Un saludo


    kintela @esekintela

    martes, 22 de julio de 2014 15:28

Todas las respuestas

  • Hola.

    Te pongo un codigo que utilice en su momento para interceptar y validar una celda en un datagrid de WPF.

    private void dataGridSeries_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
            {
                
                // Obtengo el numero de fila seleccionado
                fila = e.Row.GetIndex();
                // Obtengo el numero de columna seleccionada
                int columna= e.Column.DisplayIndex;
                // Obtengo lo que hay escrito en la celda en modo edición.
                FrameworkElement editado = e.EditingElement;
                // Obtengo el Item de toda la fila
                DataRowView filagrid = (DataRowView) e.Row.Item;
                // Instancio array con el mismo numero de posiciones que de Items
                string[] a = new string[filagrid.Row.ItemArray.Length];
                TextBox texto = (TextBox)editado;
                // Recorro todas las posiciones del item para cambiar y validar el dato introducido.
                for (int con = 0; con <= filagrid.Row.ItemArray.Length - 1; con++) 
                {
                    a[con] = filagrid.Row.ItemArray[con].ToString();
                }
                try
                {
                    // Mi metodo para validar y cambiar punto por coma
                    Validacion valido = new Validacion();
                    texto.Text = valido.CambiaAComa(texto.Text);
                    if (valido.EsNumero(texto.Text))
                    {
                        a[columna] = texto.Text;
                    }
                    else 
                    {
                        a[columna] = "0";
                    }
                }
                
                    // Si hay algun error el valor pasara a ser cero
                catch (Exception) { a[columna] = "0"; }
                
                // Cargo lo editado en el Item
                filagrid.Row.ItemArray = a;
                // Fuerzo la terminación de la edición
                filagrid.EndEdit();
                // LLamo metodo para calcular errores y medias
                errores[fila] = Calculos.Error(filagrid);
                // Nuleo y vuelvo a cargar los datos para actualizar
                dataGridErrores.ItemsSource = null;
                dataGridErrores.ItemsSource = errores;
                Cambios();
            }

    En este codigo hay clases y metodos creados por mi que no sabras que son exactamente como Calculos y Validacion pero no son importantes, la idea principal son las 5 o 6 primeras lineas que es donde consigo los datos de la celda y en las ultimas lineas que es donde se vuelve a cargar los datos actualizados y validados.

    Espero te sea de útilidad. Un saludo.


    Es de buena educación dar las gracias cuando te ayudan, si alguna respuesta te ha sido útil agradécelo marcándola como útil.

    miércoles, 9 de julio de 2014 8:49
  • Hola

    Muchas Gracias por la ayuda. Me ha servido para ver como acceder al valor de la celda editada, pero mi problemática es que estoy usando un datagrid de WPF con el patrón MVVM (Model View ViewModel) con lo que la Vista  donde se muestra el datagrid tiene un ViewModel (una clase) como datacontext  y luego el itemsource del datagrid es una propiedad de ese ViewModel que en mi caso es una lista de entidades cada una de las cuales tiene X propiedades entre las que están los días del mes y una para el total con lo que se muestran una serie de filas editables con un calendario. Al editar una fila automáticamente en el evento que me comentas yo ya tengo actualizado el ViewModel asociado a la fila editada y la entidad del modelo que rellena ese ViewModel y por consiguiente la propiedad Total pero lo que no consigo hacer es que la columna del total en el gris se actualice en consecuencia.

    Una vez que obtengo la fila del gris editada y el valor editado gracias a tu código

    // Obtengo el numero de fila seleccionado
    int numFila = e.Row.GetIndex();
    // Obtengo el numero de columna seleccionada
    int numColumna = e.Column.DisplayIndex;
    // Obtengo lo que hay escrito en la celda en modo edición.
    FrameworkElement editado = e.EditingElement;
    TextBox texto = (TextBox)editado;
    string valor = texto.Text;             
    DataGridRow filaGrid = e.Row;

    Ahora no se como acceder al elemento correspondiente a la propiedad Total ara que en el interface se vea el valor que por detrás automáticamente ya está actualizado. Un saludo


    kintela @esekintela

    miércoles, 9 de julio de 2014 11:03
  • Por cierto.

    Si en este evento hago esto. Es decir "Refresco" el itemsource del datagrid

    CuadranteViewModel vm = (CuadranteViewModel)(this.DataContext);
    dg_Cuadrante.ItemsSource = vm.Modelo;

    El datagrid "dg_Cuadrante" no se actualiza. Pero si hago esto si. Pero claro el rendimiento es muy pobre

                    //CuadranteViewModel vm = (CuadranteViewModel)(this.DataContext);
                    //dg_Cuadrante.ItemsSource = null;
                    //dg_Cuadrante.ItemsSource = vm.Modelo;

    Un saludo


    kintela @esekintela

    miércoles, 9 de julio de 2014 11:06
  • Mira.

    Una de las cosas que estoy haciendo ahora que no se si sera muy elegante o muy efectiva, yo solo soy un mero aficionado que ademas esta empezado, es lo siguiente. Me instancio un objeto para toda la clase que es mi entidad.

    public partial class FormPatrones : UserControl
    	{
            private NegocioPatrones patronseleccionado = new NegocioPatrones();
    
    // aqui sigue todo el codigo

    luego uso el eventoSelectionChanged para tener controlado  en todo momento el item seleccionado con sus datos.

    private void dataGridPatrones_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.AddedItems.Count > 0)
                {
                    patronseleccionado = (NegocioPatrones)e.AddedItems[0];
                    dataGridHistorico.ItemsSource = new NegocioHistoricoPatrones().Cargar(patronseleccionado.Identificacion , "Historico" + tipoform);
                }
    
            }

    a partir de aqui teniendo el elemento seleccionado y con el codigo anterior podrias intentar modificarlo haber si consigues lo que deseas, por suerte ese elemento creo que es una referencia por tanto si lo modificas se vera reflejado.

    Y como ves en este caso no pongo a null el ItemsSorce y se refrescan bien los datos, tambien es cierto que lo cargo con una instancia nueva.

    Ya te digo quizad combinando estas dos cosas puedas conseguir algo.

    AAAAAA Una cosa mas. ¿Has intentado en vez de esto?

    // Obtengo el Item de toda la fila
                DataRowView filagrid = (DataRowView) e.Row.Item;


    usar e.Row.Item y combertirlo en tu entidad.

    tuentidad seleccion = (tuentidad) e.Row.Item;

    Hacer lo que tengas que hacer y luego modificarla seleccion.propiedadamodificar= valormodificado;

    Me comentas un saludo.


    Es de buena educación dar las gracias cuando te ayudan, si alguna respuesta te ha sido útil agradécelo marcándola como útil.

    miércoles, 9 de julio de 2014 11:36
  • Hola

    Muchas Gracias. Yo es que no tengo DataGridView tengo datagrid de WPF y como comenté antes el problema ahora es que ya se como acceder al valor de la celda editada pero no consigo actualizar automáticamente el valor de otra que es un total.

    Un saludo


    kintela @esekintela

    miércoles, 9 de julio de 2014 11:39
  • El codigoque he puesto en los dos casos es para WPF aunque utilice un objeto

    DataRowView

    para combertir es lo que consegui.

    Otra idea, podrias hacer que tu entidad herede de Inotificable, asi puedes hacer que cuando una propiedad cambie haya una notificacion que seria mas o menos como un evento y hacer lo que necesites, pero en este caso no puedo ayudar no lo he echo nunca y no se como funciona.. Haber si Lendro, Sergio o cualquiera que sepa un poco mas pueden contarnos un poco como funciona.


    Es de buena educación dar las gracias cuando te ayudan, si alguna respuesta te ha sido útil agradécelo marcándola como útil.


    • Editado Rodripelto miércoles, 9 de julio de 2014 11:54
    miércoles, 9 de julio de 2014 11:54
  • Hola

    El Binding del ItemsSource del datagrid con la propiedad del ViewModel está en Modo TwoWay con lo que el enlace es bidireccional entiendo...

    Un saludo y muchas Gracias


    kintela @esekintela

    miércoles, 9 de julio de 2014 12:06
  • Si creo que asi es en las dos direcciones, pero si lo omites por defecto es en las dos direcciones.

    Es de buena educación dar las gracias cuando te ayudan, si alguna respuesta te ha sido útil agradécelo marcándola como útil.

    miércoles, 9 de julio de 2014 12:27
  • Mira este enlace es lo que te comente de las notificaciones.


    Es de buena educación dar las gracias cuando te ayudan, si alguna respuesta te ha sido útil agradécelo marcándola como útil.

    miércoles, 9 de julio de 2014 13:14
  • Hola

    Al final lo he conseguido de esta manera

    En el evento CellEditEnding del datagrid tengo esto

                DataGridCell cell = GetCell(e.Row, 35);
                cell.Content = vm.Modelo[e.Row.GetIndex()].TotalFila;

    por que en la columna 35 es donde van los Totales que los saco de la propiedad TotalFila del ViewModel enlazado al datagrid

    Luego tengo estas 2 funciones

     public DataGridCell GetCell(DataGridRow row, int column)
            {
                DataGridRow rowContainer = row;

                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);

                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    if (cell == null)
                    {
                        dg_Cuadrante.ScrollIntoView(rowContainer, dg_Cuadrante.Columns[column]);
                        cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
                    }
                    return cell;
                }
                return null;
            }

            public static T GetVisualChild<T>(Visual parent) where T : Visual
            {
                T child = default(T);
                int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < numVisuals; i++)
                {
                    Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
                    child = v as T;
                    if (child == null)
                    {
                        child = GetVisualChild<T>(v);
                    }
                    if (child != null)
                    {
                        break;
                    }
                }
                return child;
            }

    Un saludo


    kintela @esekintela

    martes, 22 de julio de 2014 15:28