Если вы создадите привязку в коде, то вы можете заставить его работать. Например, простой сгенерированный код привязки:
Binding binding = new Binding("BindingPath");
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(textBoxName, TextBox.TextProperty, binding);
Поскольку путь в этой привязке («BindingPath») - это просто строка, эта строка может быть получена из любого доступного объекта.
Вам нужно будет подключиться к созданию ваших элементов данных, чтобы установить эти привязки.
Еще одна возможность, основанная на ваших комментариях:
В этом блоге описан способ создания пользовательского класса привязки путем наследования от MarkupExtension. Возможно, вы сможете использовать это в качестве отправной точки, чтобы обернуть мое предложение в повторно используемую разметку xaml для вашего специального обязательного случая.
Больше мыслей:
Хорошо, это была интересная проблема, поэтому я решил потратить немного времени на поиски рабочего решения. Заранее извиняюсь за длину следующих примеров кода ...
Основываясь на своем решении в блоге, на который я ссылался выше, я создал этот класс:
public class IndirectBinder : MarkupExtension
{
public string IndirectProperty { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
//try to get bound items for our custom work
DependencyObject targetObject;
DependencyProperty targetProperty;
bool status = TryGetTargetItems(serviceProvider, out targetObject, out targetProperty);
if (status)
{
Control targetControl = targetObject as Control;
if (targetControl == null) return null;
//Find the object to take the binding from
object dataContext = targetControl.DataContext;
if (dataContext == null) return null;
//Reflect out the indirect property and get the value
PropertyInfo pi = dataContext.GetType().GetProperty(IndirectProperty);
if (pi == null) return null;
string realProperty = pi.GetValue(dataContext, null) as string;
if (realProperty == null) return null;
//Create the binding against the inner property
Binding binding = new Binding(realProperty);
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(targetObject, targetProperty, binding);
//Return the initial value of the binding
PropertyInfo realPi = dataContext.GetType().GetProperty(realProperty);
if (realPi == null) return null;
return realPi.GetValue(dataContext, null);
}
return null;
}
protected virtual bool TryGetTargetItems(IServiceProvider provider, out DependencyObject target, out DependencyProperty dp)
{
target = null;
dp = null;
if (provider == null) return false;
//create a binding and assign it to the target
IProvideValueTarget service = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget));
if (service == null) return false;
//we need dependency objects / properties
target = service.TargetObject as DependencyObject;
dp = service.TargetProperty as DependencyProperty;
return target != null && dp != null;
}
Вы можете использовать эту новую разметку со следующим xaml:
<TextBox Text="{local:IndirectBinder IndirectProperty=FieldValuePath}"/>
Где TextBox может быть любым классом, который наследуется от элемента управления, а Text может быть любым свойством зависимости.
Очевидно, что если вам нужно предоставить какие-либо другие параметры привязки данных (например, одно или двухстороннее связывание), вам нужно добавить дополнительные свойства в класс.
Несмотря на то, что это сложное решение, одним из преимуществ использования преобразователя является то, что окончательно созданная привязка направлена против фактического внутреннего свойства, а не объекта. Это означает, что он правильно реагирует на события PropertyChanged.