How to check if a row has odd number?

2.3k views Asked by At

I'm trying to set different color for odd rows using XAML.

The datagrid in question has 3 different types of data, which I want to color differently, and simply changing AlternatingRowBackground won't do.

I'm planning on using something like

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
         <Condition Binding="{Binding Type}" Value="0"/>                         
         <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="False"/> 
         <Condition Binding="{Binding IsOddRow, RelativeSource={RelativeSource Self}}" Value="False"/>
    </MultiDataTrigger.Conditions>      
    <Setter Property="Background" Value="#FFDFE6ED"/>                   
</MultiDataTrigger>

There doesn't seem to be such a property as IsOddRow. What property should I check instead?

3

There are 3 answers

0
NGI On

Almost every answer use AlternationCount="2" but I find it a little bit too limiting. On my side I use something like AlternationCount="{ Binding MainData.ProjColl.Count}" in order to number my rows until the end ( take care it starts at 0 ! ).

In this case I need a value Converter as mentioned by @Danny Varod.

I use the converter to alternate the color of the rows ( nearly answering the question )

public class IsEvenConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        bool res = false;
        int? val = value as int?;
        if (null != val)
            res = (0 == (val % 2));
        return res;
    }     
    ...
}

And the calling XAML

<UserControl ...
<UserControl.Resources>
    ...
    <vm_nmspc:IsEvenConverter x:Key="IsEven"/>
    <Style TargetType="DataGridRow">
        <Setter Property="Width" Value="Auto"/>
        <Setter Property="Background" Value="LightGray"/>

        <!--Converter will be used below-->

        <Style.Triggers>
            ...
            <Setter Property="Background" Value="LightGray"/
            <DataTrigger Binding="{Binding  RelativeSource={RelativeSource Self},
                                            Path=(ItemsControl.AlternationIndex),
                                            Converter={StaticResource ResourceKey=IsEven}}" Value="true">
                <Setter Property="Background" Value="Lavender"/>
            </DataTrigger>
            <Trigger Property="IsMouseOver" Value="True" >
                <Setter Property="Background" Value="LightGreen"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

<Grid>
    <DataGrid ItemsSource="{Binding MainData.ProjColl}" AutoGenerateColumns="False" 
    AlternationCount="{ Binding MainData.ProjColl.Count}" >
    ...
    <DataGridTextColumn Header="Project Name" .... 

    </DataGrid>
</Grid>
</UserControl>

and some discrete screenshots

enter image description here enter image description here

Another part of the same code: Simple way to display row numbers on WPF DataGrid

0
Danny Varod On

I am not sure which grid/row type you are using, so I can't give you the exact property names, however, bind to the row's index (row number) and use a value converter (that returns true) to check if the row is odd or even.

1
Fredrik Hedblad On

You can set AlternationCount on the DataGrid and then bind to the ancestor DataGridRows attached property ItemsControl.AlternationIndex. If the value is "1" you have an odd row number.

<DataGrid ItemsSource="{Binding ...}"
          AlternationCount="2">
    <DataGrid.CellStyle>
        <Style TargetType="DataGridCell">
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Type}" Value="0"/>
                        <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                                     Path=IsSelected}"
                                   Value="False"/>
                        <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}},
                                                     Path=(ItemsControl.AlternationIndex)}"
                                   Value="1"/>
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background" Value="#FFDFE6ED"/>
                </MultiDataTrigger>
                <!-- ... -->
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>
    <!-- ... -->
</DataGrid>

Note that when binding to an attached property, you must put parentheses around the attached property. Path=(ItemsControl.AlternationIndex) will work but Path=ItemsControl.AlternationIndex won't.


Update
You could also create the property IsOddRow through an attached behavior. In the behavior you subscribe to LoadingRow. In the event handler you get the index for the loaded row and check if it is odd or not. The result is then stored in an attached property called IsOddRow which you can bind to.

To start the behavior add behaviors:DataGridBehavior.ObserveOddRow="True" to the DataGrid

<DataGrid ItemsSource="{Binding ...}"
          behaviors:DataGridBehavior.ObserveOddRow="True">
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Type}" Value="0"/>
                        <Condition Binding="{Binding Path=IsSelected,
                                                     RelativeSource={RelativeSource Self}}" Value="False"/>
                        <Condition Binding="{Binding Path=(behaviors:DataGridBehavior.IsOddRow),
                                                     RelativeSource={RelativeSource Self}}" Value="False"/>
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background" Value="#FFDFE6ED"/>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>

DataGridBehavior

public class DataGridBehavior
{
    #region ObserveOddRow

    public static readonly DependencyProperty ObserveOddRowProperty =
        DependencyProperty.RegisterAttached("ObserveOddRow",
                                            typeof(bool),
                                            typeof(DataGridBehavior),
                                            new UIPropertyMetadata(false, OnObserveOddRowChanged));
    [AttachedPropertyBrowsableForType(typeof(DataGrid))]
    public static bool GetObserveOddRow(DataGrid dataGrid)
    {
        return (bool)dataGrid.GetValue(ObserveOddRowProperty);
    }
    public static void SetObserveOddRow(DataGrid dataGrid, bool value)
    {
        dataGrid.SetValue(ObserveOddRowProperty, value);
    }

    private static void OnObserveOddRowChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dataGrid = target as DataGrid;
        dataGrid.LoadingRow += (object sender, DataGridRowEventArgs e2) =>
        {
            DataGridRow dataGridRow = e2.Row;
            bool isOddRow = dataGridRow.GetIndex() % 2 != 0;
            SetIsOddRow(dataGridRow, isOddRow);
        };
    }

    #endregion // ObserveOddRow

    #region IsOddRow

    public static DependencyProperty IsOddRowProperty =
        DependencyProperty.RegisterAttached("IsOddRow",
                                            typeof(bool),
                                            typeof(DataGridBehavior),
                                            new PropertyMetadata(false));
    [AttachedPropertyBrowsableForType(typeof(DataGridRow))]
    public static bool GetIsOddRow(DataGridRow dataGridCell)
    {
        return (bool)dataGridCell.GetValue(IsOddRowProperty);
    }
    public static void SetIsOddRow(DataGridRow dataGridCell, bool value)
    {
        dataGridCell.SetValue(IsOddRowProperty, value);
    }

    #endregion // IsOddRow
}