Привязка данных вне визуального дерева.Соединение контекста данных - PullRequest
7 голосов
/ 13 апреля 2011

Я пытаюсь привязать динамическое поведение к визуальному элементу вне логических и визуальных деревьев WPF.

Моя проблема заключается в том, что цвет графика RadChart задан в (квази-пути): RadChart.SeriesMapping.LineSeriesDefinition.Appearance.Stroke

Первоначально я хотел связать это со свойством текстового данных диаграммыв XAML.Наивно, я только что написал обычную {Binding PlotBrush}

Компилятор вернул ошибку «Не удается найти управляющий FrameWorkelement».После прочтения, я считаю, что это означает, что разрешение текстового текста в иерархии не сработало.Потому что его предки (говоря на XAML) имеют другие типы, отличные от FrameWorkElement и другие отношения, отличные от содержимого элемента управления содержимым.По крайней мере, это мое нынешнее понимание.Пожалуйста, исправьте меня.

Итак, я нашел "DataContext Bridge" http://www.codeproject.com/KB/WPF/AttachingVirtualBranches.aspx

Проще говоря, он говорит, что вы связываете свойство 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 Ответ

12 голосов
/ 13 апреля 2011

Вы нашли там хорошую статью Джоша Смита, но она немного устарела.Около года спустя тот же самый парень написал еще лучшую статью, которая в значительной степени описывает тот же вопрос, но имеет лучшие ответы: Контекст искусственного наследования

Там он использует класс 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, поэтому не могу написать полный пример, все еще надеюсь, что это поможет.

...