Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. WPF
  4. WPF Datagrid and MVVM - Binding CellStyle to a ViewModel Property

WPF Datagrid and MVVM - Binding CellStyle to a ViewModel Property

Scheduled Pinned Locked Moved WPF
wpfcsharpwcfregexarchitecture
10 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    Nicolai Schrade
    wrote on last edited by
    #1

    Hi, I'm trying desperately to get the following working, with no success :( : So I hope someone here can help me. I have a application following the MVVM pattern. A WPF datagrid should have all it's cells backgrounds set either to Yellow or White, depending on a property on the ViewModel. If the property returns "Locked", all cells should be Yellow. If the property returns "Editable", all cells should be White. Here's my XAML:

                <DataGrid x:Name="grdAnsprechpartner" Style="{Binding Path=StyleDataGrid}" 
                              AutoGenerateColumns="False" 
                              Height="auto"  Width="756" 
                              HorizontalAlignment="Left" VerticalAlignment="Top" 
                          ItemsSource="{Binding Path=AktuellerDatensatz.Personen}" >
                    <DataGrid.CellStyle>
                        <Style TargetType="{x:Type DataGridCell}">
                            <Setter Property="Background" Value="{Binding Path=CellBackground}"/>
                        </Style>
                    </DataGrid.CellStyle>
    

    ...

    The Property "CellBackground" looks like this:

    Public Overridable Property CellBackground() As SolidColorBrush
    Get
    Return p_CellBackground
    End Get
    Set(ByVal value As SolidColorBrush)
    If value.Equals(p_CellBackground) Then Return
    p_CellBackground = value
    OnPropertyChanged("CellBackground")
    End Set
    End Property

    I'm setting myViewModel.CellBackground to - for example - Brushes.Yellow. Nothing happens. What am I doing wrong? If I set the CellStyle's Background-property to a StaticResource, it works. Kind regards, Nico

    I P 2 Replies Last reply
    0
    • N Nicolai Schrade

      Hi, I'm trying desperately to get the following working, with no success :( : So I hope someone here can help me. I have a application following the MVVM pattern. A WPF datagrid should have all it's cells backgrounds set either to Yellow or White, depending on a property on the ViewModel. If the property returns "Locked", all cells should be Yellow. If the property returns "Editable", all cells should be White. Here's my XAML:

                  <DataGrid x:Name="grdAnsprechpartner" Style="{Binding Path=StyleDataGrid}" 
                                AutoGenerateColumns="False" 
                                Height="auto"  Width="756" 
                                HorizontalAlignment="Left" VerticalAlignment="Top" 
                            ItemsSource="{Binding Path=AktuellerDatensatz.Personen}" >
                      <DataGrid.CellStyle>
                          <Style TargetType="{x:Type DataGridCell}">
                              <Setter Property="Background" Value="{Binding Path=CellBackground}"/>
                          </Style>
                      </DataGrid.CellStyle>
      

      ...

      The Property "CellBackground" looks like this:

      Public Overridable Property CellBackground() As SolidColorBrush
      Get
      Return p_CellBackground
      End Get
      Set(ByVal value As SolidColorBrush)
      If value.Equals(p_CellBackground) Then Return
      p_CellBackground = value
      OnPropertyChanged("CellBackground")
      End Set
      End Property

      I'm setting myViewModel.CellBackground to - for example - Brushes.Yellow. Nothing happens. What am I doing wrong? If I set the CellStyle's Background-property to a StaticResource, it works. Kind regards, Nico

      I Offline
      I Offline
      Ian Shlasko
      wrote on last edited by
      #2

      Are you getting any binding errors? They won't pop up as exceptions, but if you look at the Output window in Visual Studio, any data binding issues should print a line there. That's usually your best way to determine whether your binding sources are correct.

      Proud to have finally moved to the A-Ark. Which one are you in?
      Author of the Guardians Saga (Sci-Fi/Fantasy novels)

      N 1 Reply Last reply
      0
      • I Ian Shlasko

        Are you getting any binding errors? They won't pop up as exceptions, but if you look at the Output window in Visual Studio, any data binding issues should print a line there. That's usually your best way to determine whether your binding sources are correct.

        Proud to have finally moved to the A-Ark. Which one are you in?
        Author of the Guardians Saga (Sci-Fi/Fantasy novels)

        N Offline
        N Offline
        Nicolai Schrade
        wrote on last edited by
        #3

        Hi, thanks a lot for your answer :) I checked the output and there IS an error:

        System.Windows.Data Error: 40 : BindingExpression path error: 'CellBackground' property not found on 'object' ''Person' (HashCode=51777710)'. BindingExpression:Path=CellBackground; DataItem='Person' (HashCode=51777710); target element is 'DataGridCell' (Name=''); target property is 'Background' (type 'Brush')

        Now I see, the datagrid's ItemsSource is bound to an ObservableCollection of "Personen". But I don't know how to get this solved. How do I tell the CellStyle's binding, it should look for "CellBackground" on the ViewModel? Regards, Nico

        I 1 Reply Last reply
        0
        • N Nicolai Schrade

          Hi, thanks a lot for your answer :) I checked the output and there IS an error:

          System.Windows.Data Error: 40 : BindingExpression path error: 'CellBackground' property not found on 'object' ''Person' (HashCode=51777710)'. BindingExpression:Path=CellBackground; DataItem='Person' (HashCode=51777710); target element is 'DataGridCell' (Name=''); target property is 'Background' (type 'Brush')

          Now I see, the datagrid's ItemsSource is bound to an ObservableCollection of "Personen". But I don't know how to get this solved. How do I tell the CellStyle's binding, it should look for "CellBackground" on the ViewModel? Regards, Nico

          I Offline
          I Offline
          Ian Shlasko
          wrote on last edited by
          #4

          If you want to bind to properties on the ViewModel, then your grid needs to be bound to the ViewModel. Each row of the grid is bound to one item in the ItemsSource, so that's where it's looking for "CellBackground"

          Proud to have finally moved to the A-Ark. Which one are you in?
          Author of the Guardians Saga (Sci-Fi/Fantasy novels)

          N 1 Reply Last reply
          0
          • I Ian Shlasko

            If you want to bind to properties on the ViewModel, then your grid needs to be bound to the ViewModel. Each row of the grid is bound to one item in the ItemsSource, so that's where it's looking for "CellBackground"

            Proud to have finally moved to the A-Ark. Which one are you in?
            Author of the Guardians Saga (Sci-Fi/Fantasy novels)

            N Offline
            N Offline
            Nicolai Schrade
            wrote on last edited by
            #5

            I'm not sure I understand your answer, sorry. The datagrid's ItemsSource is bound to the ViewModel (it is bound to a ViewModel's property of type ObservableCollection). What I did now is:

                            <DataGrid.CellStyle>
                                <Style TargetType="{x:Type DataGridCell}">
                                    <Setter Property="Foreground" Value="Black"/>
            
                                    <Setter Property="Background" 
                                   Value="{Binding Path=DataContext.CellBackground, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}"/>
                                </Style>
                            </DataGrid.CellStyle>
            

            This works, but I'm sure that's not the most elegant solution...

            I 1 Reply Last reply
            0
            • N Nicolai Schrade

              Hi, I'm trying desperately to get the following working, with no success :( : So I hope someone here can help me. I have a application following the MVVM pattern. A WPF datagrid should have all it's cells backgrounds set either to Yellow or White, depending on a property on the ViewModel. If the property returns "Locked", all cells should be Yellow. If the property returns "Editable", all cells should be White. Here's my XAML:

                          <DataGrid x:Name="grdAnsprechpartner" Style="{Binding Path=StyleDataGrid}" 
                                        AutoGenerateColumns="False" 
                                        Height="auto"  Width="756" 
                                        HorizontalAlignment="Left" VerticalAlignment="Top" 
                                    ItemsSource="{Binding Path=AktuellerDatensatz.Personen}" >
                              <DataGrid.CellStyle>
                                  <Style TargetType="{x:Type DataGridCell}">
                                      <Setter Property="Background" Value="{Binding Path=CellBackground}"/>
                                  </Style>
                              </DataGrid.CellStyle>
              

              ...

              The Property "CellBackground" looks like this:

              Public Overridable Property CellBackground() As SolidColorBrush
              Get
              Return p_CellBackground
              End Get
              Set(ByVal value As SolidColorBrush)
              If value.Equals(p_CellBackground) Then Return
              p_CellBackground = value
              OnPropertyChanged("CellBackground")
              End Set
              End Property

              I'm setting myViewModel.CellBackground to - for example - Brushes.Yellow. Nothing happens. What am I doing wrong? If I set the CellStyle's Background-property to a StaticResource, it works. Kind regards, Nico

              P Offline
              P Offline
              Pete OHanlon
              wrote on last edited by
              #6

              What you need to do is bind the background property to the actual property that contains the Locked/Editable value, and then use a value converter to change the colour as appropriate. Here's a sample of the converter:

              namespace MySample.Converters
              {
              using System;
              using System.Globalization;
              using System.Windows.Data;
              using System.Windows.Media;

              /// <summary>
              /// Converter to determine whether or not a number is negative, and apply
              /// conditional formatting if it is.
              /// </summary>
              public class StatusTextColorConverter : IValueConverter
              {
              #region IValueConverter Members
              /// <summary>
              /// Convert from the value to the colour brush.
              /// </summary>
              /// <param name="value">The value to convert.</param>
              /// <param name="targetType">The parameter is not used.</param>
              /// <param name="parameter">The parameter is not used.</param>
              /// <param name="culture">The parameter is not used.</param>
              /// <returns>The populated colour brush.</returns>
              public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
              {
              var brush = new SolidColorBrush(Colors.White);

                if (value != null && value == "Locked")
                {
                  brush = Colors.Yellow;
                }
              
                return brush;
              }
              
              /// <summary>
              /// Unused in this implementation.
              /// </summary>
              /// <param name="value">The parameter is not used.</param>
              /// <param name="targetType">The parameter is not used.</param>
              /// <param name="parameter">The parameter is not used.</param>
              /// <param name="culture">The parameter is not used.</param>
              /// <returns>The parameter is not used.</returns>
              public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
              {
                throw new NotImplementedException();
              }
              
              #endregion
              

              }
              }

              Then you declare your converter as a reference in your XAML resources:

              <conv:StatusTextColorConverter x:Key="statusTextColorConverter"/>

              (Here conv is a link to the converter namespace). Finally, you add it to your cell grid style:

              <Setter Property="Background" Value="{Binding Path=PropertyContainingEditableText, Converter={StaticResource statusTextColorConverter}}}"/>

              By doing this, you remove the need to implement a UI

              N 1 Reply Last reply
              0
              • N Nicolai Schrade

                I'm not sure I understand your answer, sorry. The datagrid's ItemsSource is bound to the ViewModel (it is bound to a ViewModel's property of type ObservableCollection). What I did now is:

                                <DataGrid.CellStyle>
                                    <Style TargetType="{x:Type DataGridCell}">
                                        <Setter Property="Foreground" Value="Black"/>
                
                                        <Setter Property="Background" 
                                       Value="{Binding Path=DataContext.CellBackground, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}}"/>
                                    </Style>
                                </DataGrid.CellStyle>
                

                This works, but I'm sure that's not the most elegant solution...

                I Offline
                I Offline
                Ian Shlasko
                wrote on last edited by
                #7

                Ahh, ok, I see where you're going with this now... I thought you wanted each cell's background to be based on the underlying data for that record, not that you wanted the entire grid to change color based on one property. A better solution might be to have each "Person" object keep a reference to the ViewModel that owns it, like a "Parent" property. That way, you can bind to Parent.CellBackground... Or if you're going to use FindAncestor (Which is a perfectly-legitimate method), you might want to source it to the DataGrid, not all the way up to the UserControl. That way, if you decide to move things around later, the grid stays modular.

                Proud to have finally moved to the A-Ark. Which one are you in?
                Author of the Guardians Saga (Sci-Fi/Fantasy novels)

                N 1 Reply Last reply
                0
                • I Ian Shlasko

                  Ahh, ok, I see where you're going with this now... I thought you wanted each cell's background to be based on the underlying data for that record, not that you wanted the entire grid to change color based on one property. A better solution might be to have each "Person" object keep a reference to the ViewModel that owns it, like a "Parent" property. That way, you can bind to Parent.CellBackground... Or if you're going to use FindAncestor (Which is a perfectly-legitimate method), you might want to source it to the DataGrid, not all the way up to the UserControl. That way, if you decide to move things around later, the grid stays modular.

                  Proud to have finally moved to the A-Ark. Which one are you in?
                  Author of the Guardians Saga (Sci-Fi/Fantasy novels)

                  N Offline
                  N Offline
                  Nicolai Schrade
                  wrote on last edited by
                  #8

                  Okay - perfect. Thanks a lot! :)

                  1 Reply Last reply
                  0
                  • P Pete OHanlon

                    What you need to do is bind the background property to the actual property that contains the Locked/Editable value, and then use a value converter to change the colour as appropriate. Here's a sample of the converter:

                    namespace MySample.Converters
                    {
                    using System;
                    using System.Globalization;
                    using System.Windows.Data;
                    using System.Windows.Media;

                    /// <summary>
                    /// Converter to determine whether or not a number is negative, and apply
                    /// conditional formatting if it is.
                    /// </summary>
                    public class StatusTextColorConverter : IValueConverter
                    {
                    #region IValueConverter Members
                    /// <summary>
                    /// Convert from the value to the colour brush.
                    /// </summary>
                    /// <param name="value">The value to convert.</param>
                    /// <param name="targetType">The parameter is not used.</param>
                    /// <param name="parameter">The parameter is not used.</param>
                    /// <param name="culture">The parameter is not used.</param>
                    /// <returns>The populated colour brush.</returns>
                    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
                    {
                    var brush = new SolidColorBrush(Colors.White);

                      if (value != null && value == "Locked")
                      {
                        brush = Colors.Yellow;
                      }
                    
                      return brush;
                    }
                    
                    /// <summary>
                    /// Unused in this implementation.
                    /// </summary>
                    /// <param name="value">The parameter is not used.</param>
                    /// <param name="targetType">The parameter is not used.</param>
                    /// <param name="parameter">The parameter is not used.</param>
                    /// <param name="culture">The parameter is not used.</param>
                    /// <returns>The parameter is not used.</returns>
                    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
                    {
                      throw new NotImplementedException();
                    }
                    
                    #endregion
                    

                    }
                    }

                    Then you declare your converter as a reference in your XAML resources:

                    <conv:StatusTextColorConverter x:Key="statusTextColorConverter"/>

                    (Here conv is a link to the converter namespace). Finally, you add it to your cell grid style:

                    <Setter Property="Background" Value="{Binding Path=PropertyContainingEditableText, Converter={StaticResource statusTextColorConverter}}}"/>

                    By doing this, you remove the need to implement a UI

                    N Offline
                    N Offline
                    Nicolai Schrade
                    wrote on last edited by
                    #9

                    Thanks a lot for your answer, i'll try this out asap. What do you mean specially with "UI based logic item"?

                    P 1 Reply Last reply
                    0
                    • N Nicolai Schrade

                      Thanks a lot for your answer, i'll try this out asap. What do you mean specially with "UI based logic item"?

                      P Offline
                      P Offline
                      Pete OHanlon
                      wrote on last edited by
                      #10

                      In this case, it means that you don't have to have a property in your ViewModel that returns a colour. The converter takes care of that for you.

                      Forgive your enemies - it messes with their heads

                      My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups