Hooking up a datacontext to WPF DataGrid colums

If you have ever wanted to do any data binding on the columns defined within a wpf data grid, you have probably quickly realized that it is not possible.  The reason why your data bindings don’t work is because the DataGrid.Columns property is attached, and therefore not part of the visual tree.  What that means is that the data context is not automatically passed down from the data grid to the grid columns.  We can, however, emulate the columns being a part of the visual tree by passing the data context down manually.   My initial source of information on how to do this lies here, however, this solution forces you to re-use your data grid’s data context which may not be desirable in all situations.  So instead i employed a slightly more flexible solution so that i could apply any data context i wanted.

I started off by creating a static extension class for the data grid modifications i need to make.  Then i add an attached property to hold the column data context.  Then i created a static constructor so that i could attach the FrameworkElement.DataContextProperty to the grid column class.  Finally, create a property changed handler for the attached property, loop through the grid columns and set the FrameworkElement.DataContextProperty to the new data context on each column.

Now in your xaml, you just need to add a binding to your attached property BELOW your column definitions.  It is imperative that you add this binding below your column definitions, or else your grid won’t contain any columns to update.  The binding syntax on your grid columns is a little more complicated than usual, just take a look at the sample code below to get an idea how to use it.  The only real difference is that you must source yourself as well as path the FrameworkElement.DataContextProperty.

After you assign the column data context property to a binding, your data grid columns will now be able to function just like any other bindable element in the visual tree.   If you just want to push the data grid data context to the columns, simple use an empty binding element instead of specifying the element name, source, or path.

Code

namespace DataGrid.Extensions
{
    using System.Windows;
    using Microsoft.Windows.Controls;

    static class DataGridExtensions
    {
        public static object GetColumnDataContext(DependencyObject obj)
        {
            return (object)obj.GetValue(ColumnDataContextProperty);
        }

        public static void SetColumnDataContext(DependencyObject obj, object value)
        {
            obj.SetValue(ColumnDataContextProperty, value);
        }

        // Using a DependencyProperty as the backing store for ColumnDataContext.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColumnDataContextProperty =
            DependencyProperty.RegisterAttached("ColumnDataContext", 
            typeof(object),
            typeof(DataGridExtensions), 
            new UIPropertyMetadata(null, ColumnDataContextChanged));

        static DataGridExtensions()
        {
            FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
        }

        private static void ColumnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UpdateColumnsDataContext(d as DataGrid, e.NewValue);
        }

        private static void UpdateColumnsDataContext(DataGrid grid, object dataContext)
        {
            if (grid != null)
            {
                foreach (var col in grid.Columns)
                {
                    col.SetValue(FrameworkElement.DataContextProperty, dataContext);
                }
            }
        }
    }
}

XAML

<wpf:DataGrid ItemsSource="{Binding Path=Channels, Mode=OneWay}" AutoGenerateColumns="False">
    <wpf:DataGrid.Columns>
        <wpf:DataGridTextColumn Header="{Binding RelativeSource={RelativeSource Self}, Path=(FrameworkElement.DataContext).DataHeader" Binding="{Binding Path=Data, Mode=OneWay}"/>
    </wpf:DataGrid.Columns>
    <l:DataGridExtensions.ColumnDataContext>
        <Binding ElementName="control" Mode="OneWay" Path="HeaderNames"/>
    </l:DataGridExtensions.ColumnDataContext>
</wpf:DataGrid>

Fixing Missing PDF Thumbnails

I was dealing with this issue a little while ago, and found it is really difficult to get PDF files to generate their thumbnail in vista or windows 7.  The solution i found, which seems to work quite well, is actually quite simple.  First off, I was unable to get Acrobat Pro to generate thumbnails at all, if anyone has a solution for that let me know.  My solution was to first change the default program of PDF’s to Acrobat Reader (version 9 i think).  This should update the icons of your PDF’s (if they were previously opening with Acrobat Pro).  Now open Acrobat Reader (without a PDF file, just the program is all we need), and then go File -> Open…  Now update your view to Extra Large Icons and navigate to the folder that contains the PDF’s which you want to generate thumbnails for.  The open dialog will generate them for you as soon as they come into view, and as a bonus, the thumbnails stick with windows explorer.

Hope this helps out anyone else facing this issue.  Please leave comments if it didn’t work for you or if you have a better way.

Edmonton Tennis Courts

Just a quick posting that i had planned to do over a year ago. Way back when i first got myself into tennis mode, I started scanning Edmonton for tennis courts. I did the scanning on google maps, and my result was a pretty filled set of tennis courts in and around Edmonton. And i mean PRETTY DAMN FILLED, as in, even private backyard courts are marked (sorry if this is your back yard court, i am just being complete). While the private courts are probably not of any use, the public and semi-private ones might be. So here is the map. It is open for collaboration, so please do not vandalize it, and please contribute if you have anything new.

EDIT: Sorry, i accidentally added a space in the link, it is now fixed.

Edmonton and Area Tennis Courts

« Previous PageNext Page »