суббота, 1 января 2022 г.

Навигация с помощью MVVM

 

Навигация с помощью MVVM


Когда я только начинал работать с MVVM, я не понимал, как перемещаться между страницами. Я твердо верю в использование ViewModels для всего (кроме кода, специфичного для View), и что пользовательский интерфейс - это просто удобный интерфейс для ваших ViewModels. Я не хотел создавать кнопку на странице, которая имеет какой-либо код программной части для переключения страниц, и мне не нравилась идея распределения моей навигации по всем моделям просмотра.

В конце концов я понял, что решение было простым: мне нужна была ViewModel для самого приложения, которая содержала бы состояние приложения, например CurrentPage.

Вот пример, основанный на простом примере MVVM .

ViewModel

Обычно я называю ViewModel ApplicationViewModel или ShellViewModel, но вы можете называть это как хотите. Это стартовая страница приложения, и обычно это единственный объект страницы или окна в моем проекте.

Обычно он содержит

List<ViewModelBase> PageViewModels
ViewModelBase CurrentPage
ICommand ChangePageCommand

Вот пример ApplicationViewModel, который я бы использовал для простого примера MVVM .

public class ApplicationViewModel : ObservableObject
{
    #region Fields
 
    private ICommand _changePageCommand;
 
    private IPageViewModel _currentPageViewModel;
    private List<IPageViewModel> _pageViewModels;
 
    #endregion
 
    public ApplicationViewModel()
    {
        // Add available pages
        PageViewModels.Add(new HomeViewModel());
        PageViewModels.Add(new ProductsViewModel());
 
        // Set starting page
        CurrentPageViewModel = PageViewModels[0];
    }
 
    #region Properties / Commands
 
    public ICommand ChangePageCommand
    {
        get
        {
            if (_changePageCommand == null)
            {
                _changePageCommand = new RelayCommand(
                    p => ChangeViewModel((IPageViewModel)p),
                    p => p is IPageViewModel);
            }
 
            return _changePageCommand;
        }
    }
 
    public List<IPageViewModel> PageViewModels
    {
        get
        {
            if (_pageViewModels == null)
                _pageViewModels = new List<IPageViewModel>();
 
            return _pageViewModels;
        }
    }
 
    public IPageViewModel CurrentPageViewModel
    {
        get
        {
            return _currentPageViewModel;
        }
        set
        {
            if (_currentPageViewModel != value)
            {
                _currentPageViewModel = value;
                OnPropertyChanged("CurrentPageViewModel");
            }
        }
    }
 
    #endregion
 
    #region Methods
 
    private void ChangeViewModel(IPageViewModel viewModel)
    {
        if (!PageViewModels.Contains(viewModel))
            PageViewModels.Add(viewModel);
 
        CurrentPageViewModel = PageViewModels
            .FirstOrDefault(vm => vm == viewModel);
    }
 
    #endregion
}

Это не скомпилируется сразу, потому что я внес в него некоторые изменения. Во-первых, все мои модели PageViewModel теперь наследуются от интерфейса IPageViewModel, поэтому они могут иметь некоторые общие свойства, такие как Name.

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

Кроме того, я добавил с до продукта сек ViewModel , так как он действительно имеет дело с несколькими продуктами, а не один.

Дополнительным преимуществом наличия ViewModel для управления состоянием приложения является то, что ее также можно использовать для обработки других объектов всего приложения, таких как текущий пользователь или сообщения об ошибках.

Вид

Мне также нужен ApplicationView для моей ApplicationViewModel. Он должен содержать какой-то вид навигации, который показывает список моделей PageViewModel, и щелчок по PageViewModel должен выполнять команду ChangePage.

Он также должен содержать элемент управления для отображения свойства CurrentPage, и я обычно использую для этого ContentControl. Это позволяет мне использовать DataTemplates, чтобы сообщить WPF, как рисовать каждую модель IPageViewModel.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 год
22
23
24
25
26
27
28 год
29
30
31 год
32
<Window x:Class="SimpleMVVMExample.ApplicationView"
        xmlns:local="clr-namespace:SimpleMVVMExample"
        Title="Simple MVVM Example" Height="350" Width="525">
 
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:HomeViewModel}">
            <local:HomeView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ProductsViewModel}">
            <local:ProductsView />
        </DataTemplate>
    </Window.Resources>
 
    <DockPanel>
        <Border DockPanel.Dock="Left" BorderBrush="Black" BorderThickness="0,0,1,0">
            <ItemsControl ItemsSource="{Binding PageViewModels}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Button Content="{Binding Name}"
                                Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                                CommandParameter="{Binding }"
                                Margin="2,5"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Border>
 
        <ContentControl Content="{Binding CurrentPageViewModel}" />
    </DockPanel>
</Window>

В этом примере я использую ItemsControl для отображения моих PageViewModels. Каждый элемент рисуется с помощью Button, а свойство Command Button привязано к ChangePageCommand.

Поскольку DataContext кнопки является PageViewModel, я использовал привязку RelativeSource, чтобы найти ChangePageCommand. Я знаю, что мое окно - это ApplicationView, а DataContext - это ApplicationViewModel, поэтому эта привязка ищет VisualTree для тега Window и привязывается к Window.DataContext.ChangePageCommand.

Также обратите внимание, что я помещаю DataTemplates в Window.Resources, чтобы сообщить WPF, как рисовать каждую модель IPageViewModel. По умолчанию, если WPF встречает в своем визуальном дереве объект, который не знает, как обрабатывать, он будет рисовать его с помощью TextBlock, содержащего метод .ToString () объекта. Определяя DataTemplate, я говорю WPF использовать определенный шаблон вместо TextBlock по умолчанию.

Если вы продолжаете использовать простой пример MVVM, я переместил ProductView из ResourceDictionary в UserControl, чтобы упростить эту задачу.

Запуск примера

Последнее, что нужно сделать, это изменить App.xaml, чтобы запускать ApplicationView и ApplicationViewModel вместо ProductView / ProductViewModel.

1
2
3
4
5
6
7
8
9
10
11
12
public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
 
        ApplicationView app = new ApplicationView();
        ApplicationViewModel context = new ApplicationViewModel();
        app.DataContext = context;
        app.Show();
    }
}

Запустите проект, и вы должны увидеть что-то похожее на изображения ниже, которые быстро переключают CurrentPage при нажатии кнопок навигации.

Снимок экрана домаДомой

Скриншот продуктовПродукты

Резюме

Вот и все. Простой пример навигации с MVVM.

Вы можете скачать исходный код этого образца здесь .

Как только вы освоитесь с WPF, я бы порекомендовал изучить использование системы обмена сообщениями, такой как Messenger MVVM Light или EventAggregator Microsoft Prism, для трансляции команд ChangePage из любой модели ViewModel, чтобы вам не нужно было искать ApplicationViewModel для выполнения ChangePageCommand, однако это в другой день.

<< Назад - Простой пример MVVM
>> Далее - Связь между моделями просмотра

113 ответов на навигацию с помощью MVVM

  1. JoachimJ говорит:

    Я знаю, что прошло много времени с тех пор, как вы опубликовали это, но это все еще полезно. Спасибо, что поделился!

  2. fwuellner84 говорит:

    Отличная статья и очень полезная в джунглях интерпретаций концепции MVVM для навигации между различными представлениями. Я намерен использовать ваш пример кода в качестве стандартного шаблона для будущей разработки приложений с несколькими представлениями в соответствии с шаблоном MVVM.

    Большое спасибо за вашу отличную работу!

    С наилучшими пожеланиями

    Другой инженер-программист

  3. Благодарный программист говорит:

    Эм… вау… Я выдергивала волосы, пытаясь понять это. Я только начал WPF и боролся с тем, как создать дизайн Master / Detail. Всякий раз, когда я щелкал по пункту меню, отображался только .ToString () модели представления. Таким образом, будет отображаться что-то вроде «ViewModels.ViewAViewModel» или что-то в этом роде. Я наткнулся на некоторые ваши ответы на SO и следил за этим блогом через них. Похоже, это богатство знаний. Спасибо, что нашли время сделать это. Это действительно помогает, и я очень ценю вашу тяжелую работу и усилия.

  4. estebanqv говорит:

    Привет Рэйчел,

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

    Как я могу интегрировать окно входа в систему в этот пример навигации, зная, что после входа пользователя в систему параметры навигации изменятся?

    Спасибо за ваш ответ

    • Рэйчел говорит:

      Есть несколько способов сделать это. Вот один пример . Лучший способ выяснить это - просто попробовать, и если вы застряли, задайте вопрос о переполнении стека с вашим кодом, ожидаемым результатом и фактическим результатом.🙂

  5. Диос говорит:

    Привет, Рэйчел. Отличная статья и блог. Два вопроса,

    Можно ли избежать списка ViewModels внутри ApplicationViewModel? Потому что я думаю, что огромный список конкретных ViewModels станет проблемой для разработчика, если проект станет более сложным.

    И вы до сих пор реализуете свои проекты таким образом?

    • Рэйчел говорит:

      Привет, Диос, к сожалению, моя текущая работа не заставляет меня работать с WPF, поэтому я мало использовал его в последние несколько лет. Да, есть способы обойти это, но я хотел, чтобы это было очень просто для цели этого сообщения в блоге. Если вы посмотрите на Google или Stack Overflow, я уверен, что вы найдете более сложные примеры🙂

  6. Рой говорит:

    Спасибо за этот пост. Я мог придумать, как работать с общим подходом (первым). Это полезно. Удачи с будущими постами.

  7. Виджай говорит:

    Не могли бы вы предоставить полный код или проект для навигации с помощью MVVM

  8. Очень хороший пост. Я просто наткнулся на ваш блог и хотел сказать, что мне очень понравилось просматривать ваши сообщения в блоге. В конце концов, я буду подписываться на вашу ленту и надеюсь, что вы скоро напишете снова!

  9. ColeG говорит:

    Привет, Рэйчел!

    Прежде всего, отличный гид. Я пытаюсь выучить C # и MVVM одновременно, и после того, что было похоже на сотни статей, именно ваша, наконец, заставила лампочки погаснуть. Спасибо за это.

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

    (Извините за размер текста на изображениях, надеюсь, вы уловили идею)

    Я попытался посмотреть сообщение stackoverflow, в котором упоминаются составные коллекции, и я попытался взять его и применить к тому, что вы продемонстрировали, но не смог заставить его работать. Вот ссылка на сообщение для справки:
    http://stackoverflow.com/questions/5473001/itemscontrol-with-multiple-datatemplates-for-a-viewmodel

    Есть идеи, как бы вы реализовали это в своем формате MVVM? Мы будем очень благодарны за любое направление или помощь. Еще раз спасибо!

  10. Спасибо, это очень помогло!

  11. www говорит:

    Большое тебе спасибо!

  12. Питер Данн говорит:

    Спасибо за время и наглядный пример. Я выделил выбранную кнопку с помощью стиля при выборе (код ниже), но мне нужна помощь, чтобы кнопка оставалась выделенной, пока я работаю в выбранном UserControl.

    Спасибо за любую помощь,
    Питер

    • Рэйчел говорит:

      Привет, Питер, попробуйте опубликовать вопрос на stackoverflow.com с соответствующими фрагментами кода, и кто-то, вероятно, может вам помочь. Если нет, просто разместите ссылку с вопросом здесь, и я постараюсь взглянуть на нее, когда у меня будет время.

  13. Eavestn говорит:

    Рэйчел, можно ли каким-либо образом использовать ваш метод обновления виртуальной машины и вытащить конфигурации .xaml DataTemplate в App.xaml?

  14. Энн Ян Пул говорит:

    У нас есть несколько приложений, которые работают в соответствии с вашим руководством, используя ViewModelLocator MVVM Light и функциональность Messenger MVVM Light. Прекрасно работает (спасибо за четкое объяснение).
    Каждая ViewModel связана с одним View. Но каждый раз, когда пользователь переходит на страницу (View), создается новый экземпляр View (ViewModels - это одиночные модели, постоянно прослушивающие сообщения), а старый не собирается сборщиком мусора. Таким образом, память становится все больше и больше, а работа приложения замедляется. Как сделать так, чтобы представление собиралось сборщиком мусора после того, как оно было выгружено?
    Я очень надеюсь, что ты сможешь мне помочь.

    • Рэйчел говорит:

      Привет Энн,

      Я не большой поклонник ViewModelLocator, поэтому не уверен, что смогу вам помочь.

      Мое лучшее предположение - дважды проверить все обработчики событий, чтобы убедиться, что ничто не удерживает View в памяти, или посмотреть, можете ли вы нарисовать View, используя DataTemplates, а не новые экземпляры. Это трудно сказать, имея мои ограниченные знания о ViewModelLocators и не видя вашего кода.

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

      Удачи!

  15. SD говорит:

    Спасибо, мс Рэйчел, за этот простой и понятный урок! Я прошу вас об этом:

    Каким будет подход, чтобы кнопка «Домашняя страница» также была * внутри * страницы продуктов (представьте, что она находится чуть ниже кнопки «получить продукт»), которая, конечно же, будет переходить на домашнюю страницу?

    Спасибо, сохраните хорошую работу! 😀

    • SD говорит:

      хмм, только что заметил последний абзац: «Я бы порекомендовал изучить использование системы обмена сообщениями, такой как Messenger MVVM Light или EventAggregator Microsoft Prism, для трансляции команд ChangePage из любой модели ViewModel»

      поскольку я изучаю MVVM, я бы хотел избежать готовых фреймворков, чтобы я действительно мог понять, что происходит (а потом я смогу использовать фреймворки). Поэтому я был бы рад, если бы вы могли дать какие-либо советы по трансляции событий / команд такого типа без использования фреймворка. (* готовится к гугл-фу *)

      Еще раз спасибо! 😀

      • Рэйчел говорит:

        Сожалею, что никогда не удосужился создать свою собственную, поэтому не уверен, смогу ли я помочь направить вас в правильном направлении. Я знаю, что существует множество вариантов таких фреймворков обмена сообщениями, некоторые из них Microsoft и некоторые сторонние, хотя я использовал только Messenger MVVM Light, EventAggregator Prism и атрибуты [EventSubscription] и [EventPublication] CAB.

    • Рэйчел говорит:

      В этом случае я бы рекомендовал использовать систему трансляции событий, такую ​​как Messenger от MVVM Light или EventAggregator от Prism. В качестве альтернативы ваш ApplicationViewModel может установить что-то вроде ProductViewModel.HomeCommandDelegate во время его создания

  16. RodAtHome говорит:

    Сделал реблог на « Докторе Кто» и прокомментировал: «
    Это отличная серия статей Рэйчел о шаблоне программирования MVVM. Стоит прочитать.

  17. RodAtHome говорит:

    Очень хорошая статья о шаблоне проектирования MVVM и навигации в приложении WPF. Спасибо за публикацию!

    У меня есть один вопрос; где определение интерфейса IPageViewModel?

  18. Франц говорит:

    Привет,

    Я попытался добавить несколько просмотров. Кнопки отображаются, но когда я нажимаю на одну из них, я получаю только имя моего класса ViewModel? Как я могу связать мою модель VIewModel с правильным представлением? И почему работает на 3 из 4?

    Заранее спасибо!

    • Рэйчел говорит:

      Привет, Франц,

      Скорее всего, у вас нет DataTemplate, определяющего тип вашего объекта ViewModel, WPF визуализирует объект с использованием шаблона по умолчанию, который представляет собой просто текст, содержащий .ToString () объекта.

      Если вы добавите свои шаблоны данных, они должны работать правильно.

      Удачи!
      Рэйчел

  19. Самамбайя младший говорит:

    Привет, я абсолютный новичок в MVVM, и я хотел бы знать об отправке данных между UserControl. Оба УК находятся на одной странице. Что-то вроде «Список и детали». Я хотел бы щелкнуть элемент списка и показать результат в детали UserControl. Как мне это сделать? Вы могли бы дать мне совет или пример?

    • Рэйчел говорит:

      Привет Самамбайя,

      В вашем примере в идеале у вас должна быть одна ViewModel как с коллекцией объектов, так и со свойством SelectedObject, и каждый UserControl будет привязан к ним. Если два объекта находятся в совершенно разных областях приложения и было бы трудно использовать одну и ту же родительскую объектную модель, я бы рекомендовал изучить систему событий WPF, такую ​​как объект Messenger MVVM Light или EventAggregator Microsoft Prism.

      Спасибо,
      Рэйчел

  20. Лам говорит:

    Привет, Рэйчел!
    Спасибо за показ этой полезной статьи, которая похожа на то, что я пытаюсь достичь в настоящее время: используйте группу переключателей (привязка команд) для переключения представлений с помощью MVVM. Однако мне не удалось заставить его работать. Можно ли проиллюстрировать своим примером кода, чтобы показать, как это можно сделать? Спасибо.

    • Рэйчел говорит:

      Привет, я,

      Я бы предложил использовать ListBox с перезаписанным стилем для использования RadioButtons, чтобы он легко отслеживал выбранный элемент. Затем вы можете привязать ItemsSource к вашим AvailableScreens и привязать SelectedItem к любому выбранному в данный момент экрану.

      Если вам нужна помощь с таким решением, попробуйте опубликовать вопрос с подробностями на http://www.stackoverflow.com и оставьте ссылку здесь для меня, и я посмотрю (при условии, что кто-то другой вам не поможет. вышел первым!).

      Удачи с этим!

  21. carpi1968 говорит:

    Привет Рэйчел,

    Замечательный пост!

    Есть ли простой способ заставить исчезнуть старый вид и исчезнуть новый вид?

    Любое предложение будет высоко оценено

  22. авоц говорит:

    Привет, к сожалению, код не может быть загружен по какой-то причине.
    Я получаю примерно следующее сообщение: «Вы подключились к wired.meraki.com, но, скорее всего, в настоящее время не подключены к устройству Cisco Meraki».

    Вы можете это проверить?
    Спасибо!

    • Рэйчел говорит:

      Привет, Avots, я не уверен, почему не работает. Я только что перепроверил ссылку, и мне кажется, что все в порядке, может быть, это проблема с вашим интернет-соединением? Я не знаю, что такое Meraki, но похоже, что это что-то особенное для вашей сети.

  23. Эсди говорит:

    отличная серия mvvm большое
    спасибо!

  24. Вой говорит:

    Спасибо за отличный пример. Как можно сделать навигацию по представлению с использованием класса MVVM Light Messenger?

    • Рэйчел говорит:

      Привет, Вой,

      Обычно мои ViewModel генерируют событие (Messenger.Default.Send) всякий раз, когда он хочет изменить текущий экран, а мой основной AppViewModel подписывается на получение этих сообщений и изменяет currentContent всякий раз, когда он его получает.

      • Вой говорит:

        Итак, должно ли событие Send быть в конструкторах всех моих моделей просмотра и событие регистрации в конструкторе основной модели представления приложения? Или событие Register должно быть в ChangePageCommand?

      • Рэйчел говорит:

        Прошло некоторое время с тех пор, как я использовал MVVM Light, однако я считаю, что он использует одноэлементный экземпляр класса Messenger, поэтому, где бы вы ни захотели изменить страницы, вы должны называть что-то вроде Messenger.Default.Send (…) и передавать его как угодно аргументы событий, которые вы хотите. Событие Register необходимо подключить только к тому классу, который отвечает за фактическое изменение представления, например к модели представления основного приложения.

  25. Дэнклик говорит:

    Привет, Рэйчел, отличные статьи, спасибо!
    Один вопрос: я хотел удалить «боковую панель кнопок» из окна ApplicationView. Итак, я реализовал навигацию следующим образом: -
    Вместо того, чтобы иметь коллекцию модели представления, при запуске приложения я устанавливаю контекст данных ApplicationWiew на новый экземпляр моего первого представления, передавая конструктору сам ApplicationViewModel:

    CurrentPageViewModel = new HomeViewModel(this)

    поэтому я вставляю ApplicationViewModel в другую модель просмотра.

    -Для выполнения навигации я создал команду, которая устанавливает CurrentPageViewModel на новый экземпляр другой модели просмотра:

    _applicationViewModel.ChangeViewModel(new AboutViewModel());

    Это хороший способ выполнить навигацию в этом сценарии?

    Спасибо!

    Даниэле

    • Рэйчел говорит:

      Привет, Даниэле, я не вижу проблем с использованием этого подхода, если он работает с вашим стилем приложения.

      Однако следует остерегаться нескольких вещей: убедиться, что для ваших ViewModel имеет смысл знать друг о друге таким образом, и это нормально - создавать новую ViewModel каждый раз, когда вызывается этот метод.

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

      Рэйчел

  26. Привет Рэйчел,

    Я заметил, что вы добавляете модели просмотра страниц в свою ApplicationViewModel. Я вижу некоторые проблемы с этим:

    1. ApplicationViewModel знает обо всех конкретных под-моделях представления.
    2. Если суб-ViewModels имеют много свойств или содержат свои собственные sub-viewModels, тогда при запуске приложения может быть открыто много viewModels, что увеличивает использование ресурсов приложением.

    Возьмем, к примеру, модульное тестирование. Если бы я тестировал ApplicationViewModel, весь граф объекта, включая HomeViewModel и ProductsViewModel, был бы в памяти. В реальном приложении у вас может быть более 10 страниц, каждая из которых может иметь свои собственные страницы (и так далее). Это кажется немного тяжелым, когда у меня должно быть максимум AppViewModel и любые имитируемые зависимости в памяти во время тестирования ApplicationViewModel.

    Кроме того, что произойдет, если модели представления, используемые в качестве страниц, будут иметь свои собственные зависимости? Кто отвечает за их решение? и если модели просмотра страниц также имеют свой собственный набор моделей просмотра страниц, каждая со своими собственными зависимостями ...

    Мне нравится простота и элегантность использования этого подхода, но при его использовании я столкнулся с проблемами, описанными выше. В настоящее время я не уверен, как лучше всего преодолеть эти препятствия.

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

    • Рэйчел говорит:

      Привет, Бенджамин,

      Типичное решение, которое я вижу, - это использование NavigationService, который отвечает за создание и управление ViewModels и связанными с ними представлениями.

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

      Раньше я также обычно использовал систему событий, такую ​​как PRISMs EventAggregator или класс Messenger MVVM Light, поэтому ViewModels не обязательно должны иметь прямую ссылку друг на друга.

      Надеюсь, это поможет ответить на ваши вопросы!
      Рэйчел

  27. Франц говорит:

    Привет Рэйчел,

    Спасибо за прекрасно написанную статью, на которую я так рад, что наткнулся на нее. Я думаю, что это хорошая модель для приложения, которое я в настоящее время конвертирую в качестве учебного опыта из Delphi 7 / VCL в F # / WPF / MVVM.

    Ваша статья помогла мне лучше понять эти новые технологии. Я почти уверен, что реорганизую приложение в его текущем состоянии, с одним представлением главного окна / виртуальной машиной и двумя (независимыми) вкладками, на несколько (в конечном итоге трех) представлений / виртуальных машин в соответствии с вашим дизайном, поскольку это намного лучше (от как с точки зрения кодирования, так и с точки зрения использования).

    С уважением,
    Франц

  28. Майкл Алиотти говорит:

    Привет, Рэйчел. Отличный пост в блоге! Однако у меня есть несколько вопросов:

    1) Как бы вы справились с передачей параметров из одной модели просмотра в другую? Другими словами, команда запускается на ViewModel1, и приложение переключается на ViewModel2, но ViewModel2 нуждается в параметре из ViewModel1.

    2) При создании экземпляра списка ViewModels, какой подход лучше всего подходит для ViewModels, которые полагаются на параметры из других ViewModels? Следует ли их добавлять в список с параметрами по умолчанию? Можно ли изменить параметры по умолчанию, когда ViewModel, от которого они зависят, передает им параметры?

    Любая помощь высоко ценится!

    • Рэйчел говорит:

      Привет Майкл,

      Обычно мы используем какую-либо систему обмена сообщениями для связи между ViewModels. Я бы порекомендовал Microsoft PRISM EventAggregator или MVVM Light Messenger, или, если вы действительно хотели, вы также могли бы вместо этого создать свой собственный.

      Если вам интересно, у меня есть их краткий обзор: Связь между ViewModels с MVVM

      Удачи с вашим проектом!

      Рэйчел

      • Майкл Алиотти говорит:

        Спасибо, Рэйчел! Я проверю ваши рекомендации.

  29. Питер говорит:

    Я заметил, что в вашем ApplicationViewModel у вас есть список ViewModel, который состоит из нового экземпляра каждой ViewModel. Может ли этот метод привести к проблемам с производительностью или это стандартный способ?

    Спасибо

    • Рэйчел говорит:

      Я уверен, что это возможно, и вы могли бы лениво загружать ViewModels по мере необходимости вместо того, чтобы создавать их все изначально. Это зависит от размера ваших ViewModels.🙂

  30. Син говорит:

    Это отличная статья, спасибо.

  31. Дено говорит:

    Как это приложение получает правильный вид ViewModel? Где указано, что HomeViewModel связана с HomeView?

    Я добавил, например, другую ViewModel в список PageViewModels, и он автоматически добавляет кнопку с правильным недавно созданным пользовательским View ... Я просто не понимаю, как это возможно? Я никогда не заявлял, что эта новая ViewModel связана с новым View.

    Command = ”{Binding DataContext.ChangePageCommand, RelativeSource = {RelativeSource AncestorType = {x: Type Window}}}”
    CommandParameter = ”{Binding}”

    Это из-за этого? Что делает Relative AncestorType = {x: Type Windows}? И почему CommandParameter ни к чему не привязан?

    C # и MVVM выглядят действительно забавным способом программирования, но для меня это довольно абстрактная техника ...

    • Рэйчел говорит:

      Привет Дено,

      ContentControl имеет свойство Content, привязанное к CurrentPageViewModel. По умолчанию WPF не знает, как рисовать ViewModel, однако я определил DataTemplate в .Resources приложения, чтобы сообщить WPF, что он должен рисовать что-либо типа HomeViewModel с HomeView и ProductsViewModel с ProductsView.

      Привязка Command только связывает событие нажатия кнопки с ChangePageCommand в ViewModel. Из-за способа наследования DataContext за элементами управления пользовательского интерфейса нам нужно использовать привязку RelativeSource, чтобы указать ему искать в Window.DataContext для ChangePageCommand. Пустая привязка - это просто ярлык для ссылки на текущий DataContext, поэтому он передает выбранную модель IPageViewModel этой команде.

      Если вы новичок в WPF, я бы посоветовал прочитать мои статьи « Понимание изменения мышления при переходе от Winforms к WPF» и « Что это за« DataContext », о котором вы говорите? Я думаю, они могут помочь ответить на некоторые ваши вопросы, связанные с привязками, DataContext и MVVM.

      • Дено говорит:

        Вау, спасибо за быстрый ответ ... и этот блог содержит очень полезную информацию, я не знал об этой огромной базовой статье WPF. Я значительно улучшился с тех пор, как задал этот вопрос, но я все еще новичок, поэтому я все еще собираюсь изучить это ... спасибо!

      • Раджеш говорит:

        Привет Рэйчел,

        В статье вы упомянули, что «DataContext кнопки является PageViewModel, поэтому вы использовали привязку RelativeSource для поиска ChangePageCommand».
        Я изо всех сил пытаюсь понять, почему DataContext кнопки является PageViewModel? Не могли бы вы пролить свет на это.
        Я прочитал вашу статью, объясняющую DataContext, из которой я могу сделать вывод, что если DataContext не установлен для элемента, он наследует его от родительского элемента. Здесь я вижу, что DataContext не указан ни для одного элемента, кроме элемента Window (указанного в App.xaml.cs), DataContext которого является ApplicationViewModel. Итак, для меня Datacontext кнопки должен быть ApplicationViewModel.
        Что я здесь неправильно думаю?

      • Рэйчел говорит:

        Привет, Раджеш, чтобы понять здесь наследование DataContext, вам нужно понять, как работает ItemsControl.

        ItemsControl возьмет каждый элемент в ItemsSource, создаст копию объектов пользовательского интерфейса в ItemsPanelTemplate и назначит DataContext этих объектов пользовательского интерфейса, равный элементу в ItemsSource. Вы можете узнать больше о ItemsControl здесь, если вам интересно.

        Итак, в этом случае ItemsControl привязан к коллекции PageViewModels, поэтому он создаст экземпляр ItemsPanelTemplate для каждой PageViewModel и назначит DataContext, равный PageViewModels [n] для каждой из них.

        Надеюсь, это поможет,
        Рэйчел

  32. Уолтер говорит:

    Спасибо за этот пример,

    Я никогда раньше не использовал свою виртуальную машину для навигации, и у меня есть вопрос по ApplicationView.

    Мне нравится использовать (изменить стиль) радиокнопки для переключения представлений. Таким образом, пользователь может видеть, какой вид выбран. Как насчет установки правильного радиокнопки на IsChecked при изменении представления в модели представления.

    Уолтер

    • Рэйчел говорит:

      Привет, Уолтер,

      Обычно для чего-то подобного, где я хочу отслеживать SelectedItem, я бы использовал ListBox, стилизованный под использование RadioButtons. Вы можете найти здесь пример .

      Удачи с этим,
      Рэйчел

  33. Фарид говорит:

    Привет Рэйчел,

    Большое спасибо. Это именно то, что я искал на этой неделе!
    Теперь я хотел бы использовать встроенный элемент управления Ribbon для загрузки моих моделей просмотра.
    Я пытался изменить ваш источник, чтобы сделать это, но моя кнопка ленты всегда отключена ???

    • Рэйчел говорит:

      Привет, Фарид, возможно, ты захочешь задать вопрос об этом на StackOverflow вместе с небольшим образцом исходного кода.

      Раньше я не работал с элементом управления Ribbon и не очень помог бы, если бы не увидел ваш код.

      Спасибо,
      Рэйчел

  34. Навид Квадри говорит:

    Привет, Рэйчел,
    я (новичок в WPF) работаю над приложением на основе навигации, где у меня около 10 просмотров. Я пытаюсь понять, почему мы не используем NavigationService, встроенный в WPF.
    Я был бы очень признателен, если бы вы могли рассказать мне или указать на ресурс по этой теме.
    Спасибо,
    Навид

    • Рэйчел говорит:

      Привет, Навид,

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

      Мне всегда было проще позволить моему приложению (ViewModels) управлять потоком приложения и полностью исключить пользовательский интерфейс из уровней приложения.

      Для меня слой пользовательского интерфейса - это просто визуальное представление уровня моего приложения, и мне не нравилось, когда мой уровень приложения беспокоился о том, как рисовать каждую страницу.

  35. Митеш говорит:

    Привет!

    Мой вопрос связан со следующей статьей, в которой вы разместили свой ответ.

    Ссылка: http://stackoverflow.com/questions/7446825/open-child-window-inside-a-parent-window-in-wpf-using-mvvm

    Я использую структуру MVVM и технику, которую вы упомянули в своем следующем сообщении.

    https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/

    Это тот же метод, который я использую для реализации своего приложения WPF. Я создаю новое приложение WPF и хочу использовать чистый MVVM, т.е. без кода.
    Теперь я хочу открыть диалоговое окно или дочернее окно поверх окна приложения, нажав кнопку в текущем окне приложения. В этом окне я хочу показать некоторые данные в сетке данных и предоставить возможность хранить эти данные в сетке для поиска определенных данных в сетке, а затем хочу предоставить пользователю функциональность, в которой пользователь может выбрать конкретную строку из сетки и нажать «ОК» или «Отменить».
    Теперь моя проблема: как я могу открыть это окно поверх окна приложения? Как я могу узнать, какую запись выбрал пользователь? и как только пользователь нажимает «ОК» или «Отмена», я хочу, чтобы это окно закрылось и выполнило некоторую операцию на основе выбора.

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

    Заранее спасибо.

    Митеш.

    • Рэйчел говорит:

      Привет, Митеш,

      Для меня это обычно зависит от того, какой это диалог.

      Если это что-то вроде диалогового окна «Файл / Папка», я обычно обращаюсь к нему со слоя ViewModel.

      Если это что-то вроде всплывающего окна, содержащего дочерний контент, я обычно использую настраиваемый элемент управления Popup Control в моем слое пользовательского интерфейса и управляю такими свойствами, как IsPopupVisible и PopupContent, из слоя ViewModel.

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

      В вашем примере я бы, вероятно, выбрал второй вариант, когда ViewModel будет содержать содержимое диалогового окна (включая SaveCommand и CancelCommand), а XAML будет написан за такое время, чтобы он обеспечивал визуальное представление данных вашего диалогового окна, когда это необходимо. .

  36. Адам Адам говорит:

    Спасибо за эту статью, она мне очень помогла! 🙂

    • Адам говорит:

      Я пытаюсь понять, почему, когда я переключаю страницы, предыдущая страница продолжает работать, потому что, когда я добавил MessageBox к фоновому работнику на моей странице обзора, он продолжал вызывать даже на других страницах, а когда я снова щелкнул Обзор, он просто добавил еще один Обзор потому что теперь я получал 2 уведомления, увеличивающихся при нажатии кнопки «Обзор» в каждом цикле, и так далее.

      Кто-нибудь сталкивался с этой проблемой?

      • Рэйчел говорит:

        Привет, Адам,

        Убедитесь, что вы переходите на существующую ViewModel, а не создаете новую каждый раз для переключения на страницу. И не забывайте, что изменение страниц вообще не удаляет и не удаляет старую страницу - она ​​просто меняет активную страницу.

        Если у вас возникли проблемы с кодом, я бы посоветовал вам опубликовать вопрос на stackoverflow.com и включить соответствующие части вашего кода. Вы получите ответ довольно быстро, или вы можете отправить мне ссылку на свой вопрос по электронной почте, если хотите.

        Удачи с этим =)

  37. Alex F говорит:

    Здравствуйте,
    я использую ваш пример и хочу знать, как передать параметр в свой пользовательский элемент управления? В моем приложении слева будет меню (скорее всего, TreeView), и когда пользователь щелкает элемент в контекстном меню дерева, я загружаю пользовательский элемент управления с правой стороны. Пользовательскому элементу управления потребуется передать ему идентификатор или несколько параметров, чтобы он мог заполнить его View.
    Буду признателен, если вы дадите мне знать, как это реализовать.

    Спасибо.
    Алекс

    • Рэйчел говорит:

      У меня был бы объект Model, содержащий данные для вашего UserControl, в вашей ViewModel, и я просто установил бы DataContext как объект в вашей ViewModel.

      Трудно публиковать много кода в этих комментариях, но в идеале я бы хотел, чтобы моя ViewModel содержала ObservableCollection классов MyObject для TreeView.ItemsSource для привязки и свойство SelectedObject типа MyObject. Тогда я бы попросил UserControl просто привязать его DataContext к SelectedObject.

      • Alex F говорит:

        Спасибо за ответ. Я до сих пор не понимаю, как это сделать. Можно ли указать мне пример, в котором событие элемента TreeView будет переключаться между пользовательскими элементами управления и может передавать параметр пользовательскому элементу управления, чтобы он мог быть заполнен?

        Спасибо
        алекс

      • Рэйчел говорит:

        Лучший пример, который я могу найти, - это мой ответ на StackOverflow . Он использует объекты страницы, однако вы можете сделать что-то подобное со своими объектами.

        Если у вас есть дополнительные вопросы, я бы рекомендовал разместить их на этом сайте вместе с коротким примером кода, демонстрирующим вашу проблему. Они довольно хорошо умеют помочь вам быстро решить вашу проблему.

  38. Ариштат говорит:

    Хм, если вы добавите меню и привяжете команду к MenuItem аналогичным образом, MenuItem будет отключен, хотя метод CanExecute всегда возвращает true. Не могу понять почему.

    • Рэйчел говорит:

      Привет, Ариштат,

      Возможно, вы могли бы задать вопрос на StackOverflow с образцом кода, описывающим проблему, и прислать мне ссылку. Трудно сказать, в чем проблема, не видя кода, однако общая проблема, которую я вижу с меню, заключается в том, что они иногда не являются частью одного и того же визуального дерева, поэтому DataContext - это не то, что вы ожидаете.

  39. Амит Шарма говорит:

    Хороший пост, Рэйчел. При использовании этого я сталкиваюсь с проблемой (или, возможно, это связано с дизайном) - каждый раз, когда я переключаюсь на другую модель просмотра, создается новый экземпляр VIEW.

    Связывание с mainview xaml -

    Когда я переключаюсь взад и вперед, чтобы активировать ActiveViewModel - X, повторно создается представление, связанное с X (я могу проверить это, увидев, что конструктор представления попадает в отладчик).

    Это приводит к тонким ошибкам, поскольку в моем представлении есть DataGrid, и если пользователь изменил какой-либо фильтр, группы - при повторном создании экземпляра представления все эти изменения исчезнут.

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

    • Рэйчел говорит:

      Привет, Амит,

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

      Что я обычно делаю, чтобы избежать такого поведения, так это повторное использование настраиваемого элемента управления TabControl, который сохраняет ContentPresenter каждого элемента TabItem при переключении вкладок и перезагружает тот же ContentPresenter при обратном переключении. Это сохраняет состояние элемента управления, когда он не виден, и перезагружает его так же, как и при переходе от него.

      Пример кода и того, как он работает, можно найти в этом моем ответе на StackOverflow . Возможно, я напишу это решение в качестве следующего сообщения в блоге, так как я думаю, что исходный сайт, который я понял, и большая часть кода, больше не существует.🙂

      Удачи в твоем проекте,
      Рэйчел

  40. Киссак говорит:

    Привет, Рэйчел,
    я новичок в WPF и MVVC. Последовал вашему примеру, но возникла небольшая проблема. Как только я покидаю одно представление и снова возвращаюсь к нему, конструкторы ViewModel для этого представления вызываются и теряют свое состояние. Почему это так и как этого избежать?

    • Рэйчел говорит:

      Привет, Киссак,

      WPF выгружает ресурсы, которые не используются, включая невидимые объекты пользовательского интерфейса, поэтому похоже, что ваше представление инициализирует новую модель представления в качестве своего контекста данных при загрузке представления, что обычно не является тем, что я рекомендую.

      Проверьте конструктор вашего представления, событие Loaded или XAML и посмотрите, не устанавливается ли DataContext где-нибудь в новый экземпляр вашей модели ViewModel.

      • Киссак говорит:

        Привет, Рэйчел, представление было одним из более старых экспериментов, в котором контекст данных устанавливался в XAML, поэтому ViewModel был воссоздан. Когда я его удалил, состояние сохраняется. Спасибо за уделенное время…

      • Лора говорит:

        Привет, у меня такая же проблема, не могли бы вы ее объяснить? Я не знаю, как настроить DataContext, чтобы не терять состояние. Спасибо.

      • Рэйчел говорит:

        Привет, Лора,

        Если ваши текущие привязанные элементы управления, похоже, теряют свое состояние, то вы, вероятно, сбрасываете DataContext, к которому они привязаны, например, вручную устанавливаете DataContext в коде ваших элементов управления.

        Обычно вы не хотите когда-либо устанавливать DataContext из кода, стоящего за вашими UserControls, поскольку вы должны передавать DataContext в свой UserControl во время его использования, а его явная установка в коде программной части предотвратит это.

        Если вы изо всех сил пытаетесь понять DataContext, я бы порекомендовал прочитать недавнее сообщение в блоге, которое я написал: Что это за «DataContext», о котором вы говорите?

        Удачи с этим,
        Рэйчел

  41. Джефф говорит:

    Спасибо, Рэйчел!

  42. Джефф говорит:

    Хороший пример. Работа над дизайном торговой точки, где начальным экраном является вход с клавиатуры. Итак, в этом примере я пытаюсь понять, как начать работу с представлением входа в систему. Как только пользователь войдет в систему, перейдите на домашнюю страницу ???

    • Рэйчел говорит:

      Раньше, когда я делал экран входа в систему, я показывал и проверял вход в систему еще до того, как основное приложение запускалось в методе OnStartup файла app.xaml.cs.

      защищенное переопределение void OnStartup (StartupEventArgs e)
      {
          base.OnStartup (e);
      
          var login = new LoginDialog ();
          var loginVm = новый LoginViewModel ();
      
          login.DataContext = loginVm;
          login.ShowDialog ();
      
          если (! login.DialogResult.GetValueOrDefault ())
          {
              Environment.Exit (0);
          }
      
          // При условии успешного входа в систему, запускаем приложение
          var app = new ShellView ();
          var context = new ShellViewModel (loginVm.CurrentUser);
          app.DataContext = context;
          app.Show ();
      }

      Надеюсь, это поможет =)

      • Джефф говорит:

        Хорошо, имеет смысл. Вопрос, по вашему предложению я добавил диалоговое окно журнала, которое появляется при запуске. Однако после входа в систему приложение просто закрывается (ShellView никогда не появляется). Что-нибудь пришло в голову?

      • Рэйчел говорит:

        Установите для Application.ShutdownMode значение, отличное от значения по умолчанию OnLastWindowClose. Я обычно использую OnExplicitShutdown

      • Хэл говорит:

        Привет, Рэйчел

        Что я должен передать в мою функцию входа в систему (окно logindialog), чтобы закрыть его, а затем открыть ShellView, пробовал разные решения, и ничего не случилось, чтобы открыть ShellView ...

        Я даже добавил «Application.ShutdownMode: как вы писали ранее.

        Заранее спасибо.

      • Рэйчел говорит:

        Привет, Хэл, если вы используете ShowDialog для отображения окна входа в систему, тогда код в вашем OnStartup должен возобновиться, как только ваш диалог входа в систему вернет DialogResult

  43. Нилоу говорит:

    Хороший пример,

    Пробовал использовать это в своем приложении, потому что я не хотел использовать Prism для этого небольшого приложения.

    Единственное, что я хочу изменить, это вместо того, чтобы помещать все кнопки в shellview / applicationview, я просто хочу зарегистрировать представления в shellview. Затем добавление кнопок в разных представлениях, которые устанавливают для IPageViewModel CurrentPageViewModel в shellview соответствующее представление.

    Но моя проблема в том, что я не могу получить доступ к List PageViewModels из моих моделей просмотра и установить CurrentPageViewModel оттуда.

    Как я могу это решить?

    • Рэйчел говорит:

      Привет, Нилоу,

      Обычно я использую какую-то систему событий для связи между ViewModels. Обычно моя ShellViewModel прослушивает что-то вроде ChangePageEvents, и любая кнопка, которая должна изменять страницу, просто транслирует сообщение ChangePageEvent, которое будет подхвачено и выполнено ShellViewModel.

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

  44. Видар Лунд говорит:

    Рэйчел,
    спасибо за отличные примеры. Вы объясняете вещи, не предполагая, что аудитория много знает. Мне особенно понравился ваш комментарий о том, что ViewModels - это приложение, забудьте о представлениях, они просто отвлекают.
    Желаю, чтобы вы сделали этот пример с помощью MVVM Light, но я разберусь с этим. Поверьте, основное отличие состоит в том, что логика, которую вы поместили в ApplicationViewModel, должна находиться в ViewModelLocator, который загружается при запуске приложения в MVVM Light.

    • Видар Лунд говорит:

      Я разобрался. Решение заключалось в создании ShellVM верхнего уровня, которая обрабатывала бы навигацию так же, как ваша ApplicationVM. Попытка поместить логику навигации в VMLocator была ошибкой.

      • Рэйчел говорит:

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

  45. Бенджамин Гейл говорит:

    Спасибо за отличную статью.

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

    У вас есть идеи о том, как WPF управляет временем жизни каждого представления? Например, если бы у меня было большое количество представлений, между которыми нужно было переключаться, как я мог бы избавиться от представлений, которые больше не используются?

    • Рэйчел говорит:

      Привет, Бенджамин,

      WPF автоматически выгружает представление, когда оно больше не отображается. Например, если у вас есть TabControl с ViewA на одной вкладке и ViewB на другой вкладке, то переключение с вкладки ViewA на вкладку ViewB автоматически выгружает ViewA и загружает ViewB.

      • Бенджамин Гейл говорит:

        Привет, Рэйчел, спасибо за ответ.

        Применимо ли ваш комментарий выше ко всем представлениям WPF или специфичен для TabControl?

        Например, в вашем примере кода нажатие кнопки «Домой» полностью избавляет от пользовательского элемента управления продуктами?

        Известны ли вам ситуации, когда такое автоматическое поведение могло вызвать неожиданные утечки памяти?

      • Рэйчел говорит:

        Он должен применяться ко всем элементам управления, а не только к TabControl. WPF будет загружать только те элементы управления, которые в данный момент видны на экране.

      • Бенджамин Гейл говорит:

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

        Еще раз спасибо за ваш ответ, он был очень оценен. Я с нетерпением жду вашего следующего сообщения в блоге.

  46. Рикардо Дюран говорит:

    Привет Рэйчел,

    Спасибо за ваш пример навигации.

    Я новичок в WPF и MVVM, учусь.

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

    В «Список устройств» у меня есть кнопка. Когда я нажимаю кнопку, список должен быть заполнен данными.

    Моя проблема: когда я нажимаю кнопку, ничего не происходит, но если я нажимаю кнопку для вызова, например, домашней страницы, а затем нажимаю кнопку, чтобы снова вызвать «Список устройств», теперь я вижу список со всей информацией, которую я читать из базы данных.

    Вы хоть представляете эту проблему?

    Заранее спасибо за вашу помощь

    Рикардо

    • Рэйчел говорит:

      Привет, Рикардо,

      Трудно сказать, в чем проблема, не видя некоторого кода, однако я предполагаю, что кнопка находится в DeviceView, поэтому событие щелчка должно обрабатываться в DeviceViewModel через RelayCommand.

      Возможно, вы можете задать вопрос на http://www.stackoverflow.com, описав вашу проблему, вместе с примерами кода, и кто-нибудь сможет вам помочь.

      Гудлак с этим,

      Рэйчел

  47. Марк Вискочил говорит:

    Спасибо за простую для понимания, но очень мощную и полезную статью. Я использую этот метод в своем текущем проекте. Работает очень хорошо. Единственное изменение, которое я сделал, - это проверить, является ли модель представления, которую вы хотите изменить, той, на которой вы сейчас находитесь, я не меняю модель представления.

    • Рэйчел говорит:

      Привет, Марк, рад, что статья тебе понравилась!

      Определенно измените класс оболочки в соответствии с вашими потребностями и не придерживайтесь того, что у меня есть! В любом случае это не совсем конкретный класс - это скорее абстрактная идея, которую вы можете изменить, чтобы она соответствовала стилю навигации любого проекта, над которым вы работаете. Обычно это различно для каждого проекта, над которым я работаю, однако все они работают с какой-либо моделью Application или Shell ViewModel, которая имеет аналогичную концепцию.

  48. Раду говорит:

    Рэйчел,

    Мне очень нравится ваш подход, это определенно способ решить текущую проблему с навигацией. В одном из своих постов о stackoverflow, связанных с навигацией, вы рекомендовали избавиться от определения DataContext в UserControl:

    http://stackoverflow.com/questions/8677500/wpf-mvvm-load-an-usercontrol-at-runtime

    Как я могу таким образом решить проблему «смешиваемости» (пример данных, видимых в Expression Blend) пользовательских элементов управления? В настоящее время я следую методу, описанному в наборе инструментов MVVM Light. Имея класс Locator, с помощью Unity IoC он отделяет данные времени разработки от данных времени выполнения, поэтому Expression отображает образцы данных в моих пользовательских элементах управления.
    Как только я переключусь на ContentControl и DataTemplate, у меня больше не будет данных дизайна, так как DataContext, который я сейчас использую, нарушит предложенный вами подход. Не могли бы вы помочь мне с идеей, связанной с этим вопросом? Я все еще хочу, чтобы мои пользовательские элементы управления могли смешиваться.

    Большое спасибо,
    Раду

    • Рэйчел говорит:

      Привет Раду,

      Я не часто использую Expression Blend, но считаю, что вы можете использовать префикс d: для указания DataContext во время разработки. Это позволит вашим UserControls иметь DataContext в конструкторе, но не жестко закодировать DataContext в ваш UserControl.

      <UserControl
          mc:Ignorable="d"
          d:DataContext="{Binding DesignTimeDataContext}"
          ... >

      Я не уверен, но я считаю, что расширения разметки времени разработки были добавлены в VS2010, поэтому я думаю, что ViewModelLocators часто использовались до этого для решения проблемы смешиваемости, которую вы описываете. Лично мне вообще не нравится использовать ViewModelLocators (некоторые из причин можно найти здесь )

      Удачи в твоем проекте,
      Рэйчел

  49. Боб говорит:

    Очень хорошо написанная статья, Рэйчел, мне очень помогла навигация в MVVM.

    В коде, показанном выше для ApplicationViewModel, есть список для хранения моделей представления, я мог ошибаться, но ни в одном из объявлений не указан общий тип, если это не что-то вроде:

    частный список _pageViewModels;

    Если это так, я думаю, что собственность должна быть изменена, чтобы последовать ее примеру.

    Спасибо :)!

    • Рэйчел говорит:

      Спасибо, Боб, ты прав. Когда я копировал / вставлял код, он избавлялся от символов> и <и всего, что между ними. Я исправлю это.

  50. Прасант Гурупрасад говорит:

    Боже, вы все еще используете Windows XP? Когда вы планируете перейти на Win 7 (и Win 8)?

    • Рэйчел говорит:

      lol У меня на работе Windows 7, но на обоих моих домашних компьютерах стоит XP. Они созданы для игр, поэтому немного дороже, и мне пока действительно не приходилось их заменять.

Комментариев нет:

Отправить комментарий

Паттерн 'Репозиторий' в ASP.NET

  Последнее обновление: 1.11.2015         Одним из наиболее часто используемых паттернов при работе с данными является паттерн 'Репозито...