MultiBindings в Silverlight: присвоение множества привязок одному свойству - Получение DataContext
ОГЛАВЛЕНИЕ
Получение DataContext
Обычно, при определении привязки мы опускаем свойство Source, то есть {Binding Path=Forename}. Когда Binding, которое данное свойство представляет, ассоциируется с элементом, источником привязки будет (наверняка унаследован) DataContext целевого элемента. Потому для того, чтобы позволить осуществлять привязку по классу MultiBinding, он должен быть FrameworkElement, что дает нам свойство DataContext и метод SetBinding().
Тем не менее, есть одна проблема - DataContext каждого элемента наследуется от родителя в пределах визуального дерева. Наше MultiBinding не находится в пределах визуального дерева и мы не хотим, чтобы оно там было, поэтому оно не будет участвовать в наследовании DataContext. Нам необходимо обеспечить то, что когда DataContext будет изменяться по элементу, который имеет MultiBinding , связанный с ним, то мы ‘передаем’ данный DataContext к MultiBinding. С WPF это выполнить довольно легко, FrameWorkElement раскрывает событие DataContextChanged, (для зависимостей, которые не раскрывают события, всегда существует DependencyPropertyDescriptor). Тем не менее, с Silverlight нам недоступна ни одна из этих опций.
Наше решение заключается в том, чтобы создать новое привязанное свойство и привязать его к целевому (в данном случае это наш TextBlock), что потянет за собой DataContext. Следующий код скопирован из класса BindingUtil - когда класс MultiBinding ассоциируется с целевым элементом в качестве привязанного свойства, мы также привяжем его привязанное свойство DataContextPiggyBack. Мы определяем статический ( static ) метод, которые вызывается тогда, когда DatatContext целевого объекта изменяется, и мы продвигаем новый DataContext к классу MultiBinding.
/// <summary>
/// Вызывается тогда, когда свойство MultiBinding устанавливается в элементе структуры
/// </summary>
private static void OnMultiBindingChanged(DependencyObject depObj,
DependencyPropertyChangedEventArgs e)
{
FrameworkElement targetElement = depObj as FrameworkElement;
// Привязка целевых элементов DataContext, к нашему свойству DataContextPiggyBack
// Это повзоляет нам получить события изменения свойства тогда, когда изменяется targetElement DataContext
targetElement.SetBinding(BindingUtil.DataContextPiggyBackProperty, new Binding());
}
public static readonly DependencyProperty DataContextPiggyBackProperty =
DependencyProperty.RegisterAttached("DataContextPiggyBack",
typeof(object), typeof(BindingUtil), new PropertyMetadata(null,
new PropertyChangedCallback(OnDataContextPiggyBackChanged)));
public static object GetDataContextPiggyBack(DependencyObject d)
{
return (object)d.GetValue(DataContextPiggyBackProperty);
}
public static void SetDataContextPiggyBack(DependencyObject d, object value)
{
d.SetValue(DataContextPiggyBackProperty, value);
}
/// <summary>
/// Обрабатывает изменения свойства DataContextPiggyBack.
/// </summary>
private static void OnDataContextPiggyBackChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
FrameworkElement targetElement = d as FrameworkElement;
// когда изменяется targeElement DataContext мы копируем значение обновленного свойства в наш MultiBinding.
MultiBinding relay = GetMultiBinding(targetElement);
relay.DataContext = targetElement.DataContext;
}