Проектирование WPF UserControl, который получает свой DataContext от внешних элементов управления: как получить некоторые образцы данных в конструкторе, но использовать унаследованный DC во время выполнения? - PullRequest
3 голосов
/ 15 июня 2009

Я разрабатываю пользовательский элемент управления WPF, который содержит другие пользовательские элементы управления (представьте себе WidgetContainer, содержащий различные виджеты) - с использованием архитектуры M-V-VM. Во время разработки у меня есть WidgetContainerView в окне, window (View) порождает WidgetContainerViewModel в качестве его ресурса, а в конструкторе WidgetContainerViewModel без параметров я заполняю его открытую коллекцию некоторыми примерами виджетов (WidgetViewModels).

Элемент управления WidgetContainer наследует DataContext из окна, и внутри имеется ListView, который связывает виджеты с элементом управления WidgetView (который находится внутри ListView.ItemTemplate).

Теперь это работает нормально в моем WindowView, так как я вижу мои образцы виджетов, но как только я редактирую WidgetContainerView или WidgetView, контента больше нет - во время разработки элементы управления автономны, и они не наследуют никакой DataContext, поэтому Я не вижу контент, и у меня возникают проблемы при его создании (ListView пуст, поля Widget также ...).

Я попытался добавить образец виджета в WidgetView:

public partial class WidgetView : UserControl
{
    public WidgetView()
    {
        InitializeComponent();
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
        {
            //btw, MessageBox.Show(...) here sometimes crashes my Visual Studio (2008), but I have seen the message - this code gets executed at design time, but with some lag - I saw the message on reload of designer, but at that time, I have already commented it - wtf?
            this.DataContext = new WidgetViewModel(); //creates sample widget
        }
    }
}

но это не сработало - я все еще ничего не вижу в конструкторе.

Я также хотел создать WidgetViewModel в качестве ресурса в WidgetView, например:

<UserControl x:Class="MVVMTestWidgetsControl.View.WidgetView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="WidgetViewModel" //this doesn't work!
    Height="Auto" Width="Auto">
    <UserControl.Resources>
        <ResourceDictionary>
            <ViewModel:WidgetViewModel x:Key="WidgetViewModel" />
        </ResourceDictionary>
    </UserControl.Resources>

    <TextBlock Text="{Binding Path=Title}"></TextBlock>

</UserControl>

но я не знаю, как назначить WidgetViewModel как DataContext всего виджета - я не могу добавить атрибут DataContext в UserControl, потому что WidgetViewModel определяется позже в коде. Есть идеи, как это сделать? Я мог бы использовать пример данных таким образом и просто переопределить его в коде, чтобы он имел нужный контент во время выполнения ...

Каковы ваши лучшие практики при разработке пользовательских элементов управления? Спасибо, разработка пустого элемента управления неинтересна :)).

Ответы [ 2 ]

3 голосов
/ 16 июня 2009

Во втором фрагменте вы можете ссылаться на свой DataContext как DynamicResource:

DataContext="{DynamicResource WidgetViewModel}"

Но большинство пользовательских элементов управления имеют своего рода контейнер макета верхнего уровня, и вы можете установить DataContext для этого контейнера как StaticResource.

В вашем случае, однако, вы можете подумать об удалении части кода вашего ВМ, так как вы пишете пользовательский UserControl. Вы должны спросить себя, какие преимущества вы получаете от полностью автономной ViewModel без реальной модели поддержки, разработанной только для одного View (то есть пользовательского UserControl). Возможно, вы могли бы просто определить некоторые DependencyProperties и использовать их?

1 голос
/ 17 июня 2009

Я придумал несколько решений: добавить DC в качестве ресурса (он будет автоматически создан с помощью конструктора без параметров) и выполнить следующее в коде View:

    public PanelView()
    {
        InitializeComponent();

        if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())) //DeleteAtRelease:
        {
            //we are in runtime, reset DC to have it inherited
            this.DataContextHolder.DataContext = DependencyProperty.UnsetValue;
        }

    }

Лучшим способом было бы назначать DC только тогда, когда мы находимся во время разработки, но VS это не нравилось - это работало только иногда и совершенно недетерминировано, а когда-то даже падало.

Другая проверка на время проектирования:

        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
        {
            this.DataContext = new WidgetViewModel();
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...