WPF - Какие условия должны быть выполнены, чтобы использовать привязку данных в элементах контента пользовательского элемента управления? - PullRequest
3 голосов
/ 28 апреля 2009

Я нахожусь в процессе создания пользовательского элемента управления - в частности, круговой диаграммы. Я хочу, чтобы разметка выглядела примерно так:

<c:PieChart>
    <!-- These dependency properties are never set -->
    <c:Slice Value="{Binding RedCount}" />
    <c:Slice Value="{Binding BlueCount}" />
    <c:Slice Value="{Binding GreenCount}" />
</c:PieChart>

PieChart происходит от Control:

[ContentProperty("Slices")]
public class PieChart : Control
{
    public PieChart()
    {
        Slices = new ObservableCollection<Slice>();
    }

    public ObservableCollection<Slice> Slices { get; private set; }
}

Приведенный выше XAML вызывает заполнение свойства Slices тремя экземплярами Slice.

Вот фрагмент из Slice:

public class Slice : ContentControl
{
    public static DependencyProperty ValueProperty
        = DependencyProperty.Register(
            "Value", typeof(double), typeof(Slice),
            new PropertyMetadata((p,a) => ((Slice)p).OnValueChanged(a)));

    private void OnValueChanged(DependencyPropertyChangedEventArgs e)
    {
        // This code never called!
    }
}

Проблема в в том, что свойство Value для Slice никогда не устанавливается. Если я добавлю свойство зависимостей в PieChart и скопирую выражение привязки, то значение будет установлено, поэтому я уверен, что понимаю основы свойств зависимостей и привязок.

Итак, что мне нужно сделать, чтобы мое свойство зависимости установило значение для дочернего элемента? Поскольку эти предметы находятся в моей собственной коллекции, они каким-то образом не находятся в логическом дереве, распознаваемом какой-либо магией, заставляющей работать привязки?

Простой ответ «сделай это» был бы полезен, но мне бы очень хотелось понять, что здесь происходит не так, поэтому я приму самый проницательный, объяснительный ответ, опубликованный.

РЕДАКТИРОВАТЬ Я не дал понять, но на DataContext объекта PieChart есть некоторый окружающий объект, который содержит свойства RedCount и т. Д. В прошлом, когда я ' У меня была опечатка в пути привязки (или какая-то другая ошибка). Я видел предупреждения в окне вывода VS во время выполнения. В этом случае я ничего не вижу.

Ответы [ 2 ]

3 голосов
/ 28 апреля 2009

Похоже, что Slice элементы управления не подключены к визуальному дереву. Это просто переменные-члены, и WPF не знает, что они должны отображаться как дочерние элементы PieChart. Пара возможных подходов:

Есть PieChart вызов AddLogicalChild для добавления Slice объектов. Вам необходимо учитывать возможность добавления или удаления Slice из коллекции во время выполнения. Это довольно низкий уровень: MSDN рекомендует: «Для авторов элементов управления манипулирование логическим деревом на этом уровне не рекомендуется, если только ни одна из моделей контента для доступных базовых классов управления не подходит для вашего сценария управления. Рассмотрите возможность создания подклассов на уровне ContentControl, ItemsControl и HeaderedItemsControl. "

Сделать PieChart a Panel. В этом случае Slice будут его потомками, но учтите, что свойство Children имеет слабый тип, поэтому люди могут добавить в PieChart что угодно. Это не плохая или хорошая вещь; это рассмотрение проекта (см. примечание ниже). Но это, вероятно, не то, что вы хотите в вашем случае.

Сделать PieChart и ItemsControl и переопределить GetContainerForItemOverride, IsItemItsOwnContainerOverride и, возможно, PrepareContainerForItemOverride создать / уважать Slice управления. (См. ListBox и ListBoxItem, ComboBox и ComboBoxItem и т. Д.) Приятной особенностью этого является то, что пользователи могут затем использовать ItemsSource и DataTemplate (например, ListBox) вместо необходимости создавать дочерние элементы управления вручную. (Но пользователи по-прежнему могут создавать фиксированные Slice в XAML в соответствии с вашим синтаксисом, так же, как они могут создавать ListBoxItems в XAML.)

Вы могли бы даже рассмотреть гибридный подход, например, выделение функциональности радиальной компоновки в RadialLayoutPanel и генерация кругового среза в ItemsControl, которая использует RadialLayoutPanel в качестве ItemsPanel.

0 голосов
/ 28 апреля 2009

Я думаю, что проблема, которую вы видите, состоит в том, что привязки пытаются использовать неправильный источник. Я подозреваю, что что-то вроде этого будет работать для вас:

<c:PieChart>
    <!-- These dependency properties are never set -->
    <c:Slice Value="{Binding RedCount, RelativeSource={AncestorType c:PieChart}}" />
    <c:Slice Value="{Binding BlueCount, RelativeSource={AncestorType c:PieChart}}" />
    <c:Slice Value="{Binding GreenCount, RelativeSource={AncestorType c:PieChart}}" />
</c:PieChart>

Я думаю, что это близко, но я могу быть далеко. Я не могу сейчас найти это. Но это звучит хорошо для меня. (Извините, если это совершенно не так :))

...