Привязка данных вне визуального дерева. Соединение контекста данных
Я пытаюсь привязать динамическое поведение к визуальному элементу вне логических и визуальных деревьев WPF.
Моя проблема заключается в том, что цвет графика RadChart задается в (квази-путь): RadChart.SeriesMapping.LineSeriesDefinition.Appearance.Stroke
Первоначально я хотел связать это со свойством текстового данных диаграммы в XAML. Наивно, я просто написал обычный {Binding PlotBrush}
Компилятор возвратил ошибку "Не удается найти управляющий FrameWorkelement". После прочтения, я считаю, что это означает, что разрешение текстового контекста иерархии не сработало. Поскольку его предки (говоря на XAML) имеют другие типы, отличные от FrameWorkElement и другие отношения, отличные от содержимого элемента управления содержимым. По крайней мере, это мое нынешнее понимание. Пожалуйста, поправьте меня.
Итак, я нашел "Мост DataContext" http://www.codeproject.com/KB/WPF/AttachingVirtualBranches.aspx
Проще говоря, это говорит о том, что вы связываете свойство datacontext элемента framework, которому во время выполнения присваивается текст datacontext (а не тот, который его наследует), с datacontext экземпляра FrameWorkElement в ресурсах. Затем тот же экземпляр объекта ресурса используется для привязки к свойству datacontext "ветви", которую вы хотите "присоединить" к динамике наследования DataContext. Но автору статьи была предоставлена роскошь того, что он мог осуществить валидацию прав потребителей наблюдаемой собственности. SolidColorBrush запечатан, и я предполагаю, что было бы довольно сложно реализовать полную кисть, даже используя декоратор.
В моем случае это не помогает мне делать то, что я хочу, но я "так близко". Поэтому мне интересно, есть ли какой-нибудь аспект трюков XAML, который мог бы мне помочь.
<Window.Resources>
<local:FrameWorkElement x:Key="DataContextBridge"/>
</Window.Resources>
Однако неясно, как я это использую. Нет объекта, чей текст данных должен быть установлен. AppearanceSettings не является FrameWorkElement.
<telerik:SeriesAppearanceSettings>
<telerik:SeriesAppearanceSettings.Stroke>
Ok, how do I use the fact that I can access the datacontext here?
</telerik:SeriesAppearanceSettings.Stroke>
</telerik:SeriesAppearanceSettings>
Итак, следующий шаг был более влажным, я мог каким-то образом получить объект кисти напрямую. Я экспериментировал с такими вещами, просто возился:
.cs:
public class ObservableBrush : FrameworkElement
{
public Brush Brush
{
get { return (Brush) GetValue(BrushProperty); }
set { SetValue(BrushProperty, value); }
}
public static readonly DependencyProperty BrushProperty =
DependencyProperty.Register("Brush", typeof (Brush), typeof (ObservableBrush), new UIPropertyMetadata(new SolidColorBrush(Colors.Black)));
}
Вершина XAML:
<Window.Resources>
<local:ObservableBrush x:Key="StrokeBrush"/>
</Window.Resources>
Встроенный XAML:
<telerik:SeriesAppearanceSettings.Stroke>
<Binding Path="Brush">
<Binding.Source>
<Binding Source="{StaticResource ResourceKey=StrokeBrush}" Path="DataContext"/>
</Binding.Source>
</Binding>
</telerik:SeriesAppearanceSettings.Stroke>
"Связывание" не является элементом фреймворка, равно как и "Источник" не является свойством зависимости, поэтому среда выполнения, конечно, жалуется. Мне известно, что свойство Brush никогда не будет возвращать ничего, кроме значения по умолчанию, указанного при регистрации свойства зависимостей.
Я как бы иду на второй день прямо по этой проблеме. Я думаю, что мои следующие две попытки будут: * Сделать ObservableBrush реальной кистью. Затем установите его программно (эффективно используя вместо этого стандартную динамическую привязку ресурса). Мне это не нравится Я хотел сделать работу с данными. * Мост ЩЕТКА вместо DATACONTEXT.
XAML часть этого прекрасно работает:
<telerik:SeriesAppearanceSettings.Stroke>
<Binding Source="{StaticResource ResourceKey=StrokeBrush}" Path="Brush"/>
</telerik:SeriesAppearanceSettings.Stroke>
Но опять же, как мне связать Brush со свойством DataContext? Есть ли какое-то переопределение, которое я могу использовать в ObservableBrush, чтобы Brush динамически следовал за тем, что в текстовом тексте?
Как насчет создания поддельного визуального элемента в дереве, а затем связать с ним ДВА привязки?
<!-- Within the visual tree scope -->
<SomeFrameWorkElementType>
<SomeFrameWorkElemetType.SomeBrushProp>
<Binding Source="{StaticResource ResourceKey=StrokeBrush}" Path="Brush" Mode="OneWayToSource"/>
<Binding Stroke/>
</SomeFrameWorkElemetType.SomeBrushProp>
<SomeFrameWorkElementType>
И это как-то "соединит" две привязки?
Или есть какой-то (не) официальный "класс помощника" для этого типа функциональности?
Или я лаю не на том дереве, и (намного) лучше решить эту проблему в коде через динамическое связывание ресурсов?
Любые мысли или замечания о том, как продолжить об этом? Кроме моего очевидного саморазрушения за то, что я настаивал на привязке данных, когда динамические ресурсы должны были решать это.
1 ответ
Вы нашли там хорошую статью Джоша Смита, но она немного устарела. Около года спустя тот же самый парень написал еще лучшую статью, в которой освещается практически тот же вопрос, но есть лучшие ответы: контекст искусственного наследования
Там он использует класс DataContextSpy
и пока я не до конца понимаю, чего вы пытаетесь достичь, я постараюсь показать вам, как вы это используете:
<Grid><!-- this is some container where its DataContext has the PlotBrush Property-->
<Grid.Resources>
<spy:DataContextSpy x:Key="Spy"/>
</Grid.Resources>
<telerik:thisIsYourControl>
<telerik:SeriesAppearanceSettings.Stroke>
<Binding Source="{StaticResource Spy}" Path="DataContext.PlotBrush"/>
</telerik:SeriesAppearanceSettings.Stroke>
</telerik:thisIsYourControl>
<Grid>
Я надеюсь, что это помогает и работает для вас. Раньше я не использовал элементы управления telerik, поэтому не могу написать полный пример, но все же надеюсь, что это поможет.