Turns out the only way to get this to work is to implement it like DataGridBoundColumn. The idea is to bind to the binding property. This property will internally set the binding to a private DependencyProperty. When that property changes, you can perform anything needed inside the DependencyProperty Change Callback.
Here is an example:
/// <summary>
/// Represents a System.Windows.Controls.DataGrid column that can bind to a property
/// in the grid's data source. This class provides bindable properties ending with the suffix Binding.
/// These properties will affect the properties with the same name without the suffix
/// </summary>
public class DataGridBindableTemplateColumn : DataGridBoundColumn
{
/// <summary>
/// Identifies the DataGridBindableTemplateColumn.HeaderValueProperty dependency property
/// </summary>
internal static readonly DependencyProperty HeaderValueProperty =
DependencyProperty.Register("HeaderValue", typeof(object), typeof(DataGridBindableTemplateColumn),
new PropertyMetadata(null, OnHeaderValuePropertyChanged));
/// <summary>
/// Identifies the DataGridBindableTemplateColumn.VisibilityValueProperty dependency property
/// </summary>
internal static readonly DependencyProperty VisibilityValueProperty =
DependencyProperty.Register("VisibilityValue", typeof(Visibility), typeof(DataGridBindableTemplateColumn),
new PropertyMetadata(Visibility.Visible, OnVisibilityPropertyPropertyChanged));
/// <summary>
/// The callback the fires when the VisibilityValueProperty value changes
/// </summary>
/// <param name="d">The DependencyObject from which the property changed</param>
/// <param name="e">The DependencyPropertyChangedEventArgs containing the old and new value for the depenendency property that changed.</param>
private static void OnVisibilityPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridBindableTemplateColumn sender = d as DataGridBindableTemplateColumn;
if (sender != null)
{
sender.OnVisibilityPropertyChanged((Visibility)e.OldValue, (Visibility)e.NewValue);
}
}
/// <summary>
/// The callback the fires when the HeaderValueProperty value changes
/// </summary>
/// <param name="d">The DependencyObject from which the property changed</param>
/// <param name="e">The DependencyPropertyChangedEventArgs containing the old and new value for the depenendency property that changed.</param>
private static void OnHeaderValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridBindableTemplateColumn sender = d as DataGridBindableTemplateColumn;
if (sender != null)
{
sender.OnHeaderValueChanged((object)e.OldValue, (object)e.NewValue);
}
}
private Binding _headerBinding;
private Binding _visibilityBinding;
private DataTemplate _cellEditingTemplate;
private DataTemplate _cellTemplate;
/// <summary>
/// Gets and sets the Binding object used to bind to the Header property
/// </summary>
public Binding HeaderBinding
{
get { return _headerBinding; }
set
{
if (_headerBinding != value)
{
_headerBinding = value;
if (_headerBinding != null)
{
_headerBinding.ValidatesOnExceptions = false;
_headerBinding.NotifyOnValidationError = false;
BindingOperations.SetBinding(this, HeaderValueProperty, _headerBinding);
}
}
}
}
/// <summary>
/// Gets and sets the Binding object used to bind to the Visibility property
/// </summary>
public Binding VisibilityBinding
{
get { return _visibilityBinding; }
set
{
if (_visibilityBinding != value)
{
_visibilityBinding = value;
if (_visibilityBinding != null)
{
_visibilityBinding.ValidatesOnExceptions = false;
_visibilityBinding.NotifyOnValidationError = false;
BindingOperations.SetBinding(this, VisibilityValueProperty, _visibilityBinding);
}
}
}
}
/// <summary>
/// Gets or sets the template that is used to display the contents of a cell
/// that is in editing mode.
/// </summary>
public DataTemplate CellEditingTemplate
{
get { return _cellEditingTemplate; }
set
{
if (_cellEditingTemplate != value)
{
_cellEditingTemplate = value;
}
}
}
/// <summary>
/// Gets or sets the template that is used to display the contents of a cell
/// that is not in editing mode.
/// </summary>
public DataTemplate CellTemplate
{
get { return _cellTemplate; }
set
{
if (_cellTemplate != value)
{
_cellTemplate = value;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="editingElement"></param>
/// <param name="uneditedValue"></param>
protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
{
editingElement = GenerateEditingElement(null, null);
}
/// <summary>
///
/// </summary>
/// <param name="cell"></param>
/// <param name="dataItem"></param>
/// <returns></returns>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
if (CellEditingTemplate != null)
{
return (CellEditingTemplate.LoadContent() as FrameworkElement);
}
if (CellTemplate != null)
{
return (CellTemplate.LoadContent() as FrameworkElement);
}
if (!DesignerProperties.IsInDesignTool)
{
throw new Exception(string.Format("Missing template for type '{0}'", typeof(DataGridBindableTemplateColumn)));
}
return null;
}
/// <summary>
///
/// </summary>
/// <param name="cell"></param>
/// <param name="dataItem"></param>
/// <returns></returns>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
if (CellTemplate != null)
{
return (CellTemplate.LoadContent() as FrameworkElement);
}
if (CellEditingTemplate != null)
{
return (CellEditingTemplate.LoadContent() as FrameworkElement);
}
if (!DesignerProperties.IsInDesignTool)
{
throw new Exception(string.Format("Missing template for type '{0}'", typeof(DataGridBindableTemplateColumn)));
}
return null;
}
/// <summary>
///
/// </summary>
/// <param name="editingElement"></param>
/// <param name="editingEventArgs"></param>
/// <returns></returns>
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
return null;
}
/// <summary>
///
/// </summary>
/// <param name="oldValue"></param>
/// <param name="newValue"></param>
protected virtual void OnHeaderValueChanged(object oldValue, object newValue)
{
Header = newValue;
}
/// <summary>
/// I'm to lazy to write a comment
/// </summary>
/// <param name="oldValue"></param>
/// <param name="newValue"></param>
protected virtual void OnVisibilityPropertyChanged(Visibility oldValue, Visibility newValue)
{
Visibility = newValue;
}
}
XAML:
<data:DataGridBindableTemplateColumn HeaderBinding="{Binding HeaderOne, Source={StaticResource ViewModel}}"
VisibilityBinding="{Binding HeaderOneVisibility, Source={StaticResource ViewMode}}"
HeaderStyle="{StaticResource DataColumnStyle}"
MinWidth="58">
...
</data:DataGridBindableTemplateColumn>
Hope this helps anyone with the same issue... Enjoy!