your into pulling stuff out of the visual tree now. and thats hard work, you cant find the binding because that is buried in the cell template. what i did was add my own column for this kind of stuff, the column derives from DataGridBoundColumn, which means it has a binding like all the others: ( i wrote it a while ago, it could probably do with some looking at ) This lets me just use a straight binding. i dont have to set a cell template, i can just use a DataTemplate which i like better.
public class DataGridReadOnlyObjectDisplayColumn : DataGridBoundColumn {
public DataGridReadOnlyObjectDisplayColumn() {
//set as read only,
this.IsReadOnly = true;
}
/// <summary>
/// Gets and Sets the Cell Template for this column
/// </summary>
public DataTemplate CellTemplate {
get { return (DataTemplate)GetValue(CellTemplateProperty); }
set { SetValue(CellTemplateProperty, value); }
}
// Using a DependencyProperty as the backing store for CellTemplate. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CellTemplateProperty =
DependencyProperty.Register("CellTemplate", typeof(DataTemplate), typeof(DataGridReadOnlyObjectDisplayColumn), new UIPropertyMetadata(null));
protected override System.Windows.FrameworkElement GenerateElement(DataGridCell cell, object dataItem) {
//create the simple field text block
ContentControl contentControl = new ContentControl();
contentControl.Focusable = false;
//if we have a cell template use it
if (this.CellTemplate != null) {
contentControl.SetValue(ContentControl.ContentTemplateProperty, this.CellTemplate);
}
//set the binding
ApplyBinding(contentControl, ContentPresenter.ContentProperty);
//return the text block
return contentControl;
}
/// <summary>
/// Assigns the Binding to the desired property on the target object.
/// </summary>
internal void ApplyBinding(DependencyObject target, DependencyProperty property) {
BindingBase binding = Binding;
if (binding != null) {
BindingOperations.SetBinding(target, property, binding);
}
else {
BindingOperations.ClearBinding(target, property);
}
}
protected override System.Windows.FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) {
//item never goes into edit mode it is a read only column
return GenerateElement(cell, dataItem);
}
}
now if you can get to the column you can get to the binding on the column. if you can get to the cell then you can find the data item (the row data). then what i do is follow the binding to get the cell value. it is really inefficient, and it is a hack. but it works. to follow the binding i use this.
private Object GetCellValue(Binding columnBinding, object dataSource) {
Object valueField = null;
if (columnBinding != null) {
BindingEvaluator bindingEvaluator = new BindingEvaluator();
//copy the binding
Binding binding = new Binding();
binding.Path = columnBinding.Path;
binding.Source = dataSource;
//apply the binding
BindingOperations.SetBinding(bindingEvaluator, BindingEvaluator.BindingValueProperty, binding);
//get the current cell item
valueField = bindingEvaluator.BindingValue as IValueField;
}
return valueField;
}
and the last piece is a helper class called BindingEvaluator which has one dp, that i use to follow the binding
public class BindingEvaluator : DependencyObject {
/// <summary>
/// Gets and Sets the binding value
/// </summary>
public Object BindingValue {
get { return (Object)GetValue(BindingValueProperty); }
set { SetValue(BindingValueProperty, value); }
}
// Using a DependencyProperty as the backing store for BindingValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BindingValueProperty =
DependencyProperty.Register("BindingValue", typeof(Object), typeof(BindingEvaluator), new UIPropertyMetadata(null));
}
and i call it like so:
var valueField = this.GetCellValue(column.Binding as Binding, datagrid.CurrentCell.Item);