Практикум WPF — клиент на Prism
Практикум, шаг 4 из 6. Собираем TaskDesk.Client с Prism — DI, регионы и навигация поверх MVVM. ViewModel из шага 2; API из шага 3.
Зачем Prism поверх "голого" WPF
Prism (Prism Library, открытый проект на GitHub) добавляет к MVVM:
| Возможность | Без Prism | С Prism |
|---|---|---|
| DI контейнер | Ручной new в App.xaml.cs | RegisterTypes, внедрение в VM |
| Навигация | Смена Content вручную | IRegionManager, URI TaskListView |
| Модульность | Один exe | IModule, lazy-load (в крупных системах) |
| События между VM | Связанные ссылки | IEventAggregator |
Для TaskDesk достаточно Prism.DryIoc (контейнер DryIoc в комплекте) и одного модуля с двумя View.
Пакеты и шаблон проекта
cd TaskDesk/src
dotnet new wpf -n TaskDesk.Client -o TaskDesk.Client
dotnet add TaskDesk.Client reference ../TaskDesk.Core
dotnet add TaskDesk.Client package Prism.DryIoc
dotnet add TaskDesk.Client package CommunityToolkit.Mvvm
dotnet add TaskDesk.Client package Microsoft.Extensions.Configuration.Json
Структура папок:
TaskDesk.Client/
├── App.xaml / App.xaml.cs → PrismApplication
├── Views/
│ ├── ShellWindow.xaml → оболочка с регионом
│ └── TaskListView.xaml
├── ViewModels/
│ ├── ShellViewModel.cs
│ └── TaskListViewModel.cs
├── Services/
│ └── ApiTaskRepository.cs
└── appsettings.json → BaseUrl API
PrismApplication — точка входа
App.xaml:
<prism:PrismApplication x:Class="TaskDesk.Client.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
<!-- общие стили -->
</Application.Resources>
</prism:PrismApplication>
App.xaml.cs:
Код ITЗагрузка примера кода…
Shell — окно с регионом
ShellWindow.xaml:
Код ITЗагрузка примера кода…
Prism подставляет в ContentControl View, зарегистрированную через RegisterForNavigation. DataContext ViewModel создаётся автоматически и получает зависимости из DI.
ApiTaskRepository — HttpClient к API
appsettings.json:
{
"TaskDeskApi": {
"BaseUrl": "http://localhost:5100/"
}
}
Код ITЗагрузка примера кода…
Регистрация HTTP в RegisterTypes (упрощённый вариант для учебного проекта):
container.RegisterSingleton<ITaskRepository>(c =>
{
var config = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: true)
.Build();
var baseUrl = config["TaskDeskApi:BaseUrl"] ?? "http://localhost:5100/";
var http = new HttpClient { BaseAddress = new Uri(baseUrl) };
return new ApiTaskRepository(http);
});
Конструктор ApiTaskRepository в этом случае принимает HttpClient напрямую. В production-проекте предпочтительнее IHttpClientFactory через Microsoft.Extensions.Http и named client — см. DI в .NET.
ViewModel с загрузкой при навигации
Prism поддерживает IInitializable / INavigationAware:
Код ITЗагрузка примера кода…
При каждом входе на экран список подтягивается с сервера.
Обработка ошибок сети
Код ITЗагрузка примера кода…
В View — TextBlock с красным текстом, привязанный к ErrorMessage.
EventAggregator — опционально
Если позже появится второй View ("Детали задачи"), можно оповестить список без жёсткой связи:
public class TaskChangedEvent : PubSubEvent { }
// после сохранения
_eventAggregator.GetEvent<TaskChangedEvent>().Publish();
// в TaskListViewModel — подписка в ctor, отписка в Destroy
Для минимального TaskDesk достаточно повторного LoadTasks после Create.
Запуск связки
Терминал 1:
dotnet run --project src/TaskDesk.Api --urls http://localhost:5100
Терминал 2:
dotnet run --project src/TaskDesk.Client
Чек-лист шага 4
-
PrismApplicationсоздаётShellWindowи регистрирует навигацию. -
TaskListViewModelполучаетITaskRepositoryчерез конструктор. -
ApiTaskRepositoryчитаетBaseUrlиз конфигурации. - Ошибка сети отображается в UI, приложение не падает.
Дальше: Тестирование.