views:

384

answers:

1

I have a style requirement that my data grid show the horizontal grid lines every 3 rows...

Something like this:

-----------------------------------
one  | two | three  | four   |
five | six | seven  | eight  |
nine | ten | eleven | twelve |
-----------------------------------
aaa  | bbb | ccc    | ddd    |
eee  | fff | ggg    | hhh    |
iii  | jjj | kkk    | lll    |
-----------------------------------
mmm  | nnn | ooo    | ppp    |

etc..

Does anyone know of an easy way of achieving this? I was considering updating the row style to include a border, and set the bottom border thickness to 1 every (x mod n) times, but this seems wrong.

There must be a better way?

A: 

So, after hacking away at it, I figured out a way. It is pretty nasty, but it works.

If I were in WPF, I would use the AlternationIndex and set a style trigger for index 0,1,2 and set the border thickness of index 2 to have a bottom index.

In Silverlight, we don't have AlternationIndex OR style triggers. So, I had to hack. I wrapped the code into a behavior, so my XAML is pretty clean:

Controls:DataGrid DataGridLines:HorizontalGridLineModulus.Index="3" ... />

The code to support it looks like this:

public static class HorizontalGridLineModulus
{
    private static readonly DependencyProperty HorizontalGridLineModulusBehaviorProperty =
        DependencyProperty.RegisterAttached(
            "HorizontalGridLineModulusBehavior",
            typeof (HorizontalGridLineModulusBehavior),
            typeof (DataGrid),
            null);

    public static readonly DependencyProperty IndexProperty =
        DependencyProperty.RegisterAttached(
            "Index",
            typeof (int),
            typeof (HorizontalGridLineModulus),
            new PropertyMetadata(1, IndexChanged)
            );

    public static int GetIndex(DependencyObject dependencyObject)
    {
        return (int)dependencyObject.GetValue(IndexProperty);
    }

    public static void SetIndex(DependencyObject dependencyObject, int value)
    {
        dependencyObject.SetValue(IndexProperty, value);
    }

    private static void IndexChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var behavior = dependencyObject.GetValue(HorizontalGridLineModulusBehaviorProperty) as HorizontalGridLineModulusBehavior;
        if (behavior == null)
        {
            behavior = new HorizontalGridLineModulusBehavior(dependencyObject as DataGrid, (int)e.NewValue);
            dependencyObject.SetValue(HorizontalGridLineModulusBehaviorProperty, behavior);
        }
    }

}

public class HorizontalGridLineModulusBehavior
{
    private readonly DataGrid _grid;
    private readonly int _modulus;

    public HorizontalGridLineModulusBehavior(DataGrid grid, int modulus)
    {
        if(grid == null)
            throw new ArgumentException("grid");

        _grid = grid;
        _modulus = modulus;

        _grid.LayoutUpdated += GridLayoutUpdated;
    }

    private void GridLayoutUpdated(object sender, EventArgs e)
    {
        DrawBorders();
    }

    private void DrawBorders()
    {
        var presenter = _grid.Descendants<DataGridRowsPresenter>().FirstOrDefault();
        if(presenter == null) return;

        var orderedRows = presenter.Children.OrderBy(child => RowIndex(child));

        int count = 0;
        foreach (var row in orderedRows)
        {
            count++;
            var gridLine = row.Descendants<Rectangle>().Where(x => x.Name == "BottomGridLine").FirstOrDefault();

            if(gridLine != null)
                gridLine.Visibility = count % _modulus != 0 ? Visibility.Collapsed : Visibility.Visible;
        }
    }

    private static int RowIndex(UIElement element)
    {
        var row = element as DataGridRow;
        return row == null ? 0 : row.GetIndex();
    }
}

That code makes use of a few extension methods, defined here:

public static class DependencyObjectExtensions
{
    public static IEnumerable<DependencyObject> Children(this DependencyObject element)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
            yield return VisualTreeHelper.GetChild(element, i);
    }

    public static IEnumerable<T> Children<T>(this DependencyObject element) where T : DependencyObject
    {
        return element.Children().Filter<T>();
    }

    public static IEnumerable<DependencyObject> Descendants(this DependencyObject element)
    {
        foreach (var child in element.Children())
        {
            yield return child;

            foreach (var descendent in child.Descendants())
                yield return descendent;
        }
    }

    public static IEnumerable<T> Descendants<T>(this DependencyObject element) where T : DependencyObject
    {
        return element.Descendants().Filter<T>();
    }

    public static IEnumerable<T> Filter<T>(this IEnumerable list) where T : class
    {
        foreach (var item in list)
        {
            if (item is T)
                yield return (T)item;
        }
    }
}
Brian Genisio

related questions