none
El binding asociado a la propiedad background de un DataGridRow no se me actualiza RRS feed

  • Pregunta

  • Hola

    Tengo un datagrid a cuyo Datacontext le asigno un viewmodel que entre sus propiedades hay una llamada Modelo que es una lista de entidades que son las que rellenan cada fila del datagrid y entre las propiedades de esas entidades hay una que es ColorFila que usa para colorear la fila y por lo tanto en el binding como el resto

     <DataGrid Name="dg_Cuadrante" Margin="5" Padding="5" Grid.Row="2"
                                        ItemsSource="{Binding Modelo, Mode=TwoWay}"
                                        AutoGenerateColumns="False"
                                        FrozenColumnCount="4"                                      
                                        CanUserAddRows="False"
                                        CanUserDeleteRows="False"                                   
                                        SelectionMode="Single"                          
                                        SelectionUnit="Cell"
                                        CurrentCellChanged="dg_Cuadrante_CurrentCellChanged"
                                        CellEditEnding="dg_Cuadrante_CellEditEnding">
                            <DataGrid.RowStyle>
                                <Style TargetType="DataGridRow">
                                    <Setter Property="Background">
                                        <Setter.Value>
                                            <SolidColorBrush Color="{Binding ColorFila}"/>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </DataGrid.RowStyle>

    El caso es que en la carga inicial del datagrid tengo entidades del Modelo con la propiedad ColorFila de color naranja pero no me pinta las filas de ese color. No me come el valor del bandín vamos

    Alguna idea?

    Un saludo


    kintela @esekintela

    martes, 2 de diciembre de 2014 12:07

Todas las respuestas

  • ¿Podría ser un problema del ValueConverter? Es decir, que la propiedad ColorFila traiga un tipo de valor que no se reconozca como Color?
    martes, 2 de diciembre de 2014 12:32
  • Hola.

    La propiedad trae un valor de tipo SolidColorBrush. De hecho cuando edito el valor de una de las celdas y modifico esa propiedad en función de una serie de cosas, Si que me colorea la fila. Es en la carga inicial cuando no me la colorea. Y luego una vez coloreada tras editar al mover el scroll de arriba abajo ya se monta la fiesta padre y se colorean filas al tuntun y no tengo código en el LoadingRow ni nada

    En fin, ni idea...

    Muchas Gracias y un saludo


    kintela @esekintela

    martes, 2 de diciembre de 2014 12:48
  • Qué tipo es Modelo?  Debería ser algún tipo de colección de algún otro tipo que llamaré tipo M.  Luego yo hubiera esperado era tipo M quien aportaba la propiedad ColorFila.

    Jose R. MCP
    Code Samples

    martes, 2 de diciembre de 2014 12:58
  • La propiedad trae un valor de tipo SolidColorBrush


    Lo veo un poco raro. En el background estás asignando un SolidColorBrush cuya propiedad Color es otro SolidColorBrush. Es un poco contradictorio, a no ser que exista un valueconverter que sea capaz de extraer el color a partir del solidcolorbrush para volverselo a meter al color del otro solidcolorbrush. Tal como tienes escrito el binding, lo lógico sería que la propiedad ColorFila fuera de tipo Color, no de tipo SolidColorBrush. Si es ya de tipo solidcolorbrush entonces tendrías que bindearla directamente con el background, no con otro solidcolorbrush dentro del background. Es decir, <Setter Property="Background" Value="{Binding ColorFila}" />.
    martes, 2 de diciembre de 2014 13:00
  • Hola

    Modelo es una lista de las entidades que rellenan cada fila del grid y cada entidad de esa lista tiene su propiedad ColorFila correspondiente

    public class CuadranteViewModel:ViewModelBase
        {
            #region Miembros

            private Utilidades _util = new Utilidades();

            private List<Cuadrante> _modelo;

            public List<Cuadrante> Modelo
            {
                get { return _modelo; }
                set
                {
                    _modelo = value;
                    OnPropertyChanged("Modelo");

                }
            }

    Un saludo



    kintela @esekintela

    martes, 2 de diciembre de 2014 13:05
  • El código funciona perfectamente si lo pongo en el loadingRow pero eso hace que el scroll vaya lentísimo. Ha sido al sacarlo a una función cuando deje de funcionarme y de hecho al modificar la propiedad en el evento CellEditEnding me colorea perfectamente. Es en la función de carga inicial donde no se attachés el valor bien, pero vamos que con el tipo SolidColorBrush no hay problema

    Salu2


    kintela @esekintela

    martes, 2 de diciembre de 2014 13:08
  • Hmm, muéstrenos entonces la declaración de Cuadrante y la declaración de ColorFila.  ¿Implementa INotifyPropertyChanged o bien ColorFile es dependency property?

    Jose R. MCP
    Code Samples

    martes, 2 de diciembre de 2014 13:40
  • Hola

    la entidad Cuadrante es esta

                                       

    public class Cuadrante

        {
            public string CodigoCoordinador { get; set; }
            public string Provincia { get; set; }
            public string Cadena { get; set; }
            public string Centro { get; set; }
            public string CodigoCentro { get; set; }
            public string Promotor { get; set; }
            public string PathFoto { get; set; }
            public bool Titular { get; set; }
            public int Mes { get; set; }
            public int Año { get; set; }
    public SolidColorBrush ColorFila { get; set; }
            ......

    Al dar al menú "Ver Cuadrantes" se ejecuta la función correspondiente que me obtiene los cuadrantes a mostrar:

                    List<Cuadrante> ListaCuadrantes = coordinadores.DameCuadrantes(CodigoCoordinador, Mes, Año);
                    CuadranteViewModel vmCuadrante = new CuadranteViewModel();

                    vmCuadrante.Modelo = ListaCuadrantes;

    La lista de Cuadrantes pasa a ser el contenido de la propiedad Modelo del ViewModel que rellena los datos de la Vista

    Al final asigno el ViewModel al dataContext del datagrid

    dg_Cuadrante.DataContext = vmCuadrante; 

    Donde se esperan los valores por databinding

                        <DataGrid Name="dg_Cuadrante" Margin="5" Padding="5" Grid.Row="2"
                                        ItemsSource="{Binding Modelo, Mode=TwoWay}"
                                        AutoGenerateColumns="False"
                                        FrozenColumnCount="4"                                      
                                        CanUserAddRows="False"
                                        CanUserDeleteRows="False"                                   
                                        SelectionMode="Single"                          
                                        SelectionUnit="Cell"
                                        CurrentCellChanged="dg_Cuadrante_CurrentCellChanged"
                                        CellEditEnding="dg_Cuadrante_CellEditEnding">
                            <DataGrid.RowStyle>
                                <Style TargetType="DataGridRow">
                                    <Setter Property="Background">
                                        <Setter.Value>
                                            <SolidColorBrush Color="{Binding ColorFila}"/>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </DataGrid.RowStyle>

    Antes de asociar el viewmodel al datacontext yo ya puedo observar como algunas de las entidades Cuadrante tienen la propiedad ColorFila con el valore correspondiente al color Naranja pero al mostrarse el grid todas se ponen a blanco.

    Un saludo



    kintela @esekintela

    martes, 2 de diciembre de 2014 14:50
  • Perdón se me olvidaba comentar que el ViewModel implementa la clase ViewModelBase donde se implementa a su vez INotifyPropertyChanged

     public class CuadranteViewModel:ViewModelBase
        {
            #region Miembros

            private Utilidades _util = new Utilidades();

            private List<Cuadrante> _modelo;

            public List<Cuadrante> Modelo
            {
                get { return _modelo; }
                set
                {
                    _modelo = value;
                    OnPropertyChanged("Modelo");

                }
            }

     public class ViewModelBase : INotifyPropertyChanged
        {
            #region Constructor

            protected ViewModelBase()
            {
            }

            #endregion // Constructor

            #region INotifyPropertyChanged Miembros

            /// <summary>
            /// Se dispara cuando una propiedad en este objeto toma un nuevo valor
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;

            /// <summary>
            /// Lanza el evento PropertyChanged de este objeto.
            /// </summary>
            /// <param name="propertyName">La propiedad que toma un nuevo valor</param>
            protected virtual void OnPropertyChanged(string propertyName)
            {
                this.VerifyPropertyName(propertyName);

                PropertyChangedEventHandler handler = this.PropertyChanged;
                if (handler != null)
                {
                    var e = new PropertyChangedEventArgs(propertyName);
                    handler(this, e);
                }
            }

            #endregion // INotifyPropertyChanged Members

            #region Ayudas para la depuración

            /// <summary>
            /// Avisa al desarrollador si este objeto no tiene
            /// una propiedad public con el nombre especificado.
            /// Este método no existe en la compilación Release
            /// </summary>
            [Conditional("DEBUG")]
            [DebuggerStepThrough]//Indica al depurador que recorra el código en lugar de ejecutarlo paso a paso
            public void VerifyPropertyName(string propertyName)
            {
                // Verify that the property name matches a real,  
                // public, instance property on this object.
                if (TypeDescriptor.GetProperties(this)[propertyName] == null)
                {
                    string msg = "Invalid property name: " + propertyName;

                    if (this.ThrowOnInvalidPropertyName)
                        throw new Exception(msg);
                    else
                        Debug.Fail(msg);
                }
            }

            /// <summary>
            /// Returns whether an exception is thrown, or if a Debug.Fail() is used
            /// when an invalid property name is passed to the VerifyPropertyName method.
            /// The default value is false, but subclasses used by unit tests might 
            /// override this property's getter to return true.
            /// </summary>
            protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

            #endregion // Debugging Aides

        }

    Un saludo


    kintela @esekintela

    martes, 2 de diciembre de 2014 14:52
  • Ok, basándome en lo que usted hace hice un proyecto WPF sencillo y el color de la fila aparece bien.  Estas son mis clases:

    //Clase Cuadrante:
    using System.Windows.Media;
    
    namespace WpfApplication1.Models
    {
        public class Cuadrante
        {
            public int ID { get; set; }
            public string Nombre { get; set; }
            public SolidColorBrush ColorFila { get; set; }
        }
    }
    
    //----------------------------
    //Clase ViewModelBase:
    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    
    namespace WpfApplication1.ViewModels
    {
        public class ViewModelBase : DependencyObject, INotifyPropertyChanged
        {
            #region INotifyPropertyChanged
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void RaisePropertyChanged(string propertyName)
            {
                PropertyChangedEventHandler ev = PropertyChanged;
                if (ev != null)
                {
                    ev(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
            protected bool SavePropertyAndNotify<TProp>(ref TProp storage, TProp newValue,
                [CallerMemberName] string propertyName = null)
            {
                if (Object.Equals(storage, newValue)) return false;
                storage = newValue;
                RaisePropertyChanged(propertyName);
                return true;
            }
            #endregion
        }
    }
    
    //----------------------------
    //Clase CuadranteViewModel:
    using System.Collections.Generic;
    using WpfApplication1.Models;
    
    namespace WpfApplication1.ViewModels
    {
        public class CuadranteViewModel : ViewModelBase
        {
            private List<Cuadrante> _modelo = new List<Cuadrante>();
    
            public List<Cuadrante> Modelo
            {
                get { return _modelo; }
                set { SavePropertyAndNotify(ref _modelo, value); }
            }
    
            private string _titulo = "Título por defecto";
    
            public string Titulo
            {
                get { return _titulo; }
                set { SavePropertyAndNotify(ref _titulo, value); }
            }
        }
    }

    Luego el XAML de App.xaml define una instancia estática del VM por facilidad:

    <Application x:Class="WpfApplication1.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:viewModels="clr-namespace:WpfApplication1.ViewModels"
                 xmlns:models="clr-namespace:WpfApplication1.Models"
                 StartupUri="MainWindow.xaml">
        <Application.Resources>
            <viewModels:CuadranteViewModel x:Key="CuadranteVmTest">
                <viewModels:CuadranteViewModel.Modelo>
                    <models:Cuadrante ID="1" Nombre="José"/>
                    <models:Cuadrante ID="2" Nombre="Nancy">
                        <models:Cuadrante.ColorFila>
                            <SolidColorBrush Color="GreenYellow"></SolidColorBrush>
                        </models:Cuadrante.ColorFila>
                    </models:Cuadrante>
                </viewModels:CuadranteViewModel.Modelo>
            </viewModels:CuadranteViewModel>
        </Application.Resources>
    </Application>
    

    Ahí defino una instancia de CuadranteViewModel con 2 items dentro de la colección en la propiedad Modelo, donde uno de los items (cuadrante) tiene un color de fondo especificado.

    Finalmente el XAML de la ventana:

    <Window x:Class="WpfApplication1.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"
            DataContext="{StaticResource CuadranteVmTest}"
            >
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Label Grid.Row="0" Content="{Binding Titulo}"></Label>
            <DataGrid Grid.Row="1" ItemsSource="{Binding Modelo}"
                      AutoGenerateColumns="True"
                      SelectionMode="Single"
                      SelectionUnit="Cell">
                <DataGrid.RowStyle>
                    <Style TargetType="DataGridRow">
                        <Setter Property="Background" Value="{Binding ColorFila}" />
                    </Style>
                </DataGrid.RowStyle>
            </DataGrid>
    
        </Grid>
    </Window>
    

    Aquí utilizo la instancia del VM creado en los recursos de Application y me parece que todos los binding parecen iguales a los suyos.  Eso sí, a mí sí me muestra el color de fila desde el inicio.

    Entonces no puedo reproducir el problema.  ¿Qué tengo diferente de usted?  Empecemos por el tipo de proyecto:  ¿Silverlight o WPF?  Yo hice WPF.  Luego me parece que yo inicio con el VM creado desde XAML; usted lo crea en tiempo de ejecución.  ¿Cómo?  ¿Usa el clic de un botón o algo similar?


    Jose R. MCP
    Code Samples

    martes, 2 de diciembre de 2014 15:59