2010-06-23 4 views
4

Я хочу создать элемент WPF, который во время выполнения полностью контролирует свои дочерние элементы - добавление и удаление дочернего интерфейса при изменении его свойств. Что-то немного похоже на то, что делает ItemControl при изменении свойства ItemsSource, хотя в моем случае будет только один ребенок.Элемент WPF, который динамически создает (инкапсулированных) детей во время выполнения

Это будет контейнер представления для MVVM - когда вы дадите ему модель или ViewModel, она волшебным образом создаст правильный вид и подключит все. Нет необходимости, чтобы мой контейнер просмотра был templatable (поскольку он создает пользовательские представления, которые являются UserControls и имеют свои собственные шаблоны), и я предпочел бы, чтобы он инкапсулировал как можно больше. Я мог бы, вероятно, сделать это легко, спустившись с чего-то вроде Grid и добавив дочерние элементы управления, когда меняются мои собственные свойства; но Grid публично предоставляет свою коллекцию дочерних элементов и позволяет добавлять и удалять вещи.

Какой класс WPF должен я спускаться для максимальной инкапсуляции и как добавить к нему дочерние элементы во время выполнения?

Основываясь на моем понимании документов, я попытался использовать FrameworkElement и AddVisualChild, чтобы проверить, могу ли я создавать дочерние элементы управления во время выполнения. Я не ясно, нужна ли AddLogicalChild, но я положил его в только в случае, если:

public class ViewContainer : FrameworkElement { 
    private TextBlock _child; 

    public ViewContainer() { 
     _child = new TextBlock { Text = "ViewContainer" }; 
     AddLogicalChild(_child); 
     AddVisualChild(_child); 
     InvalidateMeasure(); 
    } 

    public object Content { get; set; } 

    protected override Size ArrangeOverride(Size finalSize) { 
     _child.Arrange(new Rect(finalSize)); 
     return finalSize; 
    } 
    protected override Size MeasureOverride(Size availableSize) { 
     _child.Measure(availableSize); 
     return _child.DesiredSize; 
    } 
} 

Когда я положил ViewContainer в окно, и управлять этим, я ожидаю увидеть TextBlock, говоря «ViewContainer ». Но вместо этого я просто вижу пустое окно. Поэтому, очевидно, я что-то упускаю.

Как я могу исправить вышеуказанный код, чтобы «дочерний» элемент управления отображался во время выполнения, но не был открыт для других, с которыми можно было бы взаимодействовать (более того, чего можно избежать)?

ответ

6

Чтобы ответить на ваш конкретный вопрос, вам также необходимо переопределить GetVisualChild и VisualChildrenCount свойства, чтобы ваш дочерний элемент отображался.

+0

Прохладный - вот и все. Хотя я немного озадачен тем, почему есть AddVisualChild, если он на самом деле не добавляет его * в * ничего. –

+1

А, я вижу. Он устанавливает, чтобы ребенок знал о своем родителе; но многим родителям не нужен список детей (не имеющих ни одного или только одного), поэтому он оставляет выбор - и ответственность - хранения до родителя. Агрессивное разделение проблем: одна из вещей, которые мне очень нравятся в WPF. Но это означает, что имя «AddVisualChild» вводит в заблуждение, поскольку оно предполагает, что оно добавляет его в какой-то список, и это не так. –

0

Вы задумывались над тем, чтобы использовать поддержку WPF для неявных DataTemplates?

Способ, которым я выполнял требование, аналогичное вашему, - использовать ContentControl. Я привязываю свойство Content к моей ViewModel. Затем я убеждаюсь, что в ресурсных словарях, где-то в дереве выше ContentControl, у меня есть DataTemplates, определенные для всех типов ViewModels, которые могут быть назначены Content Property.

Таким образом, WPF позаботится о правильном подключении к ViewModel.

+0

Да, я сделал это раньше, но на этот раз я хочу сделать шаг дальше - я хочу, чтобы мой ViewContainer смог взять модель и автоматически открыть и создать для нее ViewModel, и перейти от там к Вид. Я не думаю, что DataTemplate.DataType получит меня туда без посторонней помощи. –

+0

конечно, DataTemplate.DataType не устраивает, но есть DataTemplateSelector, который может быть. –