It turned out all quite difficult.
Used articles:
Get result of a binding in code ,
Binding doesn’t have a way to copy it
1. Create a method for cloning Binding , so as not to screw up the main (taken) Binding .
public static BindingBase CloneBinding(BindingBase bindingBase, object source) { var binding = bindingBase as Binding; if (binding != null) { var result = new Binding { Source = source, AsyncState = binding.AsyncState, BindingGroupName = binding.BindingGroupName, BindsDirectlyToSource = binding.BindsDirectlyToSource, Converter = binding.Converter, ConverterCulture = binding.ConverterCulture, ConverterParameter = binding.ConverterParameter, //ElementName = binding.ElementName, FallbackValue = binding.FallbackValue, IsAsync = binding.IsAsync, Mode = binding.Mode, NotifyOnSourceUpdated = binding.NotifyOnSourceUpdated, NotifyOnTargetUpdated = binding.NotifyOnTargetUpdated, NotifyOnValidationError = binding.NotifyOnValidationError, Path = binding.Path, //RelativeSource = binding.RelativeSource, StringFormat = binding.StringFormat, TargetNullValue = binding.TargetNullValue, UpdateSourceExceptionFilter = binding.UpdateSourceExceptionFilter, UpdateSourceTrigger = binding.UpdateSourceTrigger, ValidatesOnDataErrors = binding.ValidatesOnDataErrors, ValidatesOnExceptions = binding.ValidatesOnExceptions, XPath = binding.XPath, }; foreach (var validationRule in binding.ValidationRules) { result.ValidationRules.Add(validationRule); } return result; } var multiBinding = bindingBase as MultiBinding; if (multiBinding != null) { var result = new MultiBinding { BindingGroupName = multiBinding.BindingGroupName, Converter = multiBinding.Converter, ConverterCulture = multiBinding.ConverterCulture, ConverterParameter = multiBinding.ConverterParameter, FallbackValue = multiBinding.FallbackValue, Mode = multiBinding.Mode, NotifyOnSourceUpdated = multiBinding.NotifyOnSourceUpdated, NotifyOnTargetUpdated = multiBinding.NotifyOnTargetUpdated, NotifyOnValidationError = multiBinding.NotifyOnValidationError, StringFormat = multiBinding.StringFormat, TargetNullValue = multiBinding.TargetNullValue, UpdateSourceExceptionFilter = multiBinding.UpdateSourceExceptionFilter, UpdateSourceTrigger = multiBinding.UpdateSourceTrigger, ValidatesOnDataErrors = multiBinding.ValidatesOnDataErrors, ValidatesOnExceptions = multiBinding.ValidatesOnDataErrors, }; foreach (var validationRule in multiBinding.ValidationRules) { result.ValidationRules.Add(validationRule); } foreach (var childBinding in multiBinding.Bindings) { result.Bindings.Add(CloneBinding(childBinding, source)); } return result; } var priorityBinding = bindingBase as PriorityBinding; if (priorityBinding != null) { var result = new PriorityBinding { BindingGroupName = priorityBinding.BindingGroupName, FallbackValue = priorityBinding.FallbackValue, StringFormat = priorityBinding.StringFormat, TargetNullValue = priorityBinding.TargetNullValue, }; foreach (var childBinding in priorityBinding.Bindings) { result.Bindings.Add(CloneBinding(childBinding, source)); } return result; } throw new NotSupportedException("Failed to clone binding"); }
2. Next, create a proxy object that will perform the function of translating the Binding and the resource object into a value by Binding
class DummyDO : DependencyObject { public object Value { get { return (object)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(DummyDO), new UIPropertyMetadata(null)); }
3. And the translation function Object + Binding = value
public static object EvalBinding(BindingBase b) { DummyDO d = new DummyDO(); BindingOperations.SetBinding(d, DummyDO.ValueProperty, b); return d.Value; }
4. The function returns all child elements of the specified type
public static List<T> GetVisualChilds<T>(DependencyObject parent) where T : DependencyObject { List<T> childs = new List<T>(); if (parent != null) { int numVisuals = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < numVisuals; i++) { DependencyObject v = VisualTreeHelper.GetChild(parent, i); if (v is T) childs.Add(v as T); childs.AddRange(GetVisualChilds<T>(v)); } } return childs; }
then begins a whistle dance with column types. They have 3 types
1-DataGridBoundColumn and inherited from it
2-DataGridComboBoxColumn
3-DataGridTemplateColumn
PS: ic - the list of objects by which we calculate values via Binding
for (int i = 0; i < ic.Count; ++i) for (int j = 0; j < grid.Columns.Count; ++j) { object resultValue = null; if (grid.Columns[j] is DataGridBoundColumn) { DataGridBoundColumn dgbc = (DataGridBoundColumn)grid.Columns[j]; BindingBase columnBinding = dgbc.Binding as BindingBase; BindingBase binding = CloneBinding(columnBinding, ic[i]); resultValue = EvalBinding(binding); } if (grid.Columns[j] is DataGridComboBoxColumn) { DataGridComboBoxColumn dgcbc = (DataGridComboBoxColumn)grid.Columns[j]; BindingBase binding = new Binding(dgcbc.DisplayMemberPath) { Source = ic[i] }; resultValue = EvalBinding(binding); } if (grid.Columns[j] is DataGridTemplateColumn) { DataGridTemplateColumn dgtc = (DataGridTemplateColumn)grid.Columns[j]; DataTemplate dt = dgtc.CellTemplate; ContentPresenter control = new ContentPresenter(); control.Content = ic[i]; control.DataContext = ic[i]; control.ContentTemplate = dt; control.Initialized += delegate (object c, EventArgs ea) { FrameworkElement fwe = c as FrameworkElement; fwe.ApplyTemplate(); }; control.BeginInit(); control.EndInit(); List<FrameworkElement> elems = GetVisualChilds<FrameworkElement>(control); resultValue = string.Join(" ", elems.Select(x => x is TextBlock ? ((TextBlock)x).Text : x is TextBox ? ((TextBox)x).Text : null).Where(x => x is string)); } //В resultValue будет значение равное значению в ячейке DataGrid. }
Unfortunately, there are several options:
when in DataGridTemplateColumn used ItemsControl with its ItemTemplate . in this case, we will not get a list of values of ItemsControl .
If ElementName or RelativeSource participate in Binding
If you have any thoughts on this, please respond.