Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
WPF

Как внедрить модель во viewModel?

26.12.2024, 11:19. Показов 25448. Ответов 295
Метки mvvm (Все метки)

Студворк — интернет-сервис помощи студентам
День добрый. Есть у меня метод в проекте, который вызывается из конструктора. Метод по типу "Получить все из бд и вывести на экран".

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

Теперь код.

C#
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
public class BirdsViewModel : ObservableObject
{
    // [B]Конструктор[/B]
    public BirdsViewModel(IBirdRepository birdRepository, Func<BirdEntity, BirdViewModel> birdView) // [B]Прошу обратить 
//внимание на делегат. Его, думаю, и нужно заменять.[/B]
 
    {
        Birds = [];
        _birdView = birdView;
        _birdRepository = birdRepository;
        LoadBirds();
    }
 
// [B]Проблемный метод[/B]
private async void LoadBirds()
{
    var birds = await _birdRepository.GetAllAsync(); // [B]Получение данных из БД[/B]
    switch (Name)
    {
        default:
            foreach (var bird in birds)
                Birds.Add(_birdView(bird)); // [B]С помощью делегата я во ViewModel передаю Entity, 
//с которой та и работает. Есть ли другие методы подобной реализации, чтобы у каждой ViewModel был свой Entity?[/B]
            break;
    }
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.12.2024, 11:19
Ответы с готовыми решениями:

Как из ViewModel UserControl'a изменить свойство в ViewModel главного окна?
Недавно начал попытки создавать приложение WPF с применением MVVM, и у меня возник вопрос, который не даёт мне продвигаться в разработке...

Как зарегистрировать ViewModel через Autofac, создав между ViewModel и нужным View DataContext связь?
Доброго времени суток. Есть желание при регистрации ViewModel'и сразу же &quot;подключиться&quot; к DataContext'у у нужной View, как например: ...

WPF получить доступ из одной viewmodel к другой viewmodel
Собственно есть у меня две viewmodel, mainviewmodel и settingsviewmodel, в mainviewmodel есть вот такая штука private Visibility...

295
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
29.12.2024, 12:19  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Насколько глубоко
Наверное не глубоко, я просто хочу сделать качественное приложение с быстрой работой при нарастающем объеме данных.

Я изначально RelayCommand и ObservableObject также взял из интернета и сильно не вникал в них, тут наверное нужно сделать также. С самими командами, правда, не понятно, как их писать.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
private RelayCommand<BirdEntity>? _deleteBirdCommand;
public RelayCommand<BirdEntity> DeleteBirdCommand => _deleteBirdCommand ??= new RelayCommand<BirdEntity>
(
    async bird => 
    {
        bird.Departure = Departure;
        bird.IsAlive = false;
        DeleteBirdCommand.RaiseCanExecuteChanged(); // Обновление команды
 
        await Task.Delay(2000); // Имитация долго выполнения
    },
    bird => bird.IsAlive // Почему это в конце делается? Почему после запятой? 
);
async bird - То есть тут в в параметры RelayCommand передаем какую-то переменную. Я так понял, это та, к которой идет Binding у кнопки.

DeleteBirdCommand.RaiseCanExecuteChanged (); Что значит обновление? Зачем обновлять?

В каком месте тут нужно производить сохранение изменений в бд?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
29.12.2024, 12:31
Цитата Сообщение от Vissmuy Посмотреть сообщение
bird - То есть тут в в параметры RelayCommand передаем какую-то переменную. Я так понял, это та, к которой идет Binding у кнопки.
Это то что передаётся CommandParameter. В данном случае, там пустая привязка и она передаёт текущий контекст данных, то есть bird который отображается в этой строке.

Цитата Сообщение от Vissmuy Посмотреть сообщение
DeleteBirdCommand.RaiseCanExecuteChanged ();
Состояние команды определяется методом CanExecute, в который, в данном случае, передаётся bird => bird.IsAlive.
Так как мы меняем bird.IsAlive = false;, то надо известить о том, что требуется заново проверить состояние команды.
Иногда такое обновление срабатывает автоматически, но для вложенных свойств и асинхронных методов, часто автоматически не срабатывает. И нужно "вручную" уведомлять.

Цитата Сообщение от Vissmuy Посмотреть сообщение
В каком месте тут нужно производить сохранение изменений в бд?
Вместо await Task.Delay(2000); .

Добавлено через 1 минуту
Цитата Сообщение от Vissmuy Посмотреть сообщение
Наверное не глубоко, я просто хочу сделать качественное приложение с быстрой работой при нарастающем объеме данных.
Противоречивые требования.
Если делать "качественно", то требуется влезать глубже.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
29.12.2024, 12:41  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если делать "качественно", то требуется влезать глубже.
Я ведь при этом еще смотрю на доступность знаний. То, про что вы говорите, где мне этому научиться? На ютубчике такого поди поищи. А тут никто обучать не будет, так, советы только.

Для SQLite репозиторий, как я понял, нужно будет вернуть.

Добавлено через 4 минуты
Плюс чтобы учиться и запоминать - нужно последовательно приходить к таким решениям. Я изначально вообще sql-команды вручную писал и не знал ни про DI, ни про асинхронность.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
29.12.2024, 13:10
Vissmuy, Я сейчас чуток занят. Поэтому отвечать буду по мере возможности.

Репозиторий, чтобы двигаться дальше, нужно вернуть. Для начала SQLite. Но для больших объемов и мульти пользовательской работа она плохо подходит.
Если потребуется замена на "взрослую" БД, то т это сделаем уже позже, после отладки на SQLite.

Доступность знаний.....
Они как бы доступны, но очень фрагментированы. И большой частью на английском.
То что вам нужно восполнить пробел, это даже не WPF. Это правильная реализация архитекторы приложения. WPF просто более стран в этом отношении. Реализация в MVVM, является стандартом в WPF. Она всем понятна, легко тестируется, большинство примеров и подсказок тоже будет в ней.
Поэтому, фактически, для нормального освоения WPF требуется освоение MVVM, а для него нет научиться создавать правильную архитектуру данных и приложения.

Добавлено через 9 минут
Есть много нюансов, которые мне сразу в голову приходят, но которые не так просто объяснить.
Например, между изменением свойства и сохранением в БД, есть временной лаг. И возникает коллизия отражения: представление в этом промежутке не верно отражает состояние Модели. А если произойдет отказ в сохранении, то это уже будет откровенный баг.
По простому эту коллизия не разрешить. Но она же не имеет отношения к WPF. Здесь уже возникает коллизия ваших знаний. Умей вы разрезать такие коллизии, то вопроса о них в разделе WPF даже не возникало бы.

Следующая коллизия.
В момент когда происходит сохранение GUI в текущей реализации не замораживается. И сущности могут меняться в GUI. Но ведь они уже переданы на сохранение и их изменение во время сохранения может вызвать ошибки. Соответственно, здесь тоже надо подумать над каким-то решением которое хоть и затрагивает WPF, но решать надо не средствами WPF.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
29.12.2024, 15:15  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Репозиторий, чтобы двигаться дальше, нужно вернуть
Так, я его внедряю через конструктор, но во View мне пишет, что не удалось найти доступный конструктор, где DataContext устанавливается. Нужно ли пустой конструктор рядом с не пустым создавать?

Кстати, еще хотел спросить. Таким образом действительно контекст устанавливается или только для подхвата свойств удобства ради такое делается?
XML
1
2
3
<d:FrameworkElement.DataContext>
    <vm:BirdsViewModel />
</d:FrameworkElement.DataContext>
Просто у меня в ресурсах приложения в файле App.xaml есть такое вот. Таким образом, когда я у сервис провайдера запрашиваю именно ViewModel, а не View, он мне подставляет View, ну и плюс DataContext таким образом также устанавливается.
XML
1
2
3
<DataTemplate DataType="{x:Type viewModels:BirdsViewModel}">
    <views:BirdsView />
</DataTemplate>
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
29.12.2024, 16:02
Цитата Сообщение от Vissmuy Посмотреть сообщение
Таким образом действительно контекст устанавливается или только для подхвата свойств удобства ради такое делается?
Префикс d: задаёт значения времени Разработки. В Рантайм они игнорируются: mc:Ignorable="d"

Добавлено через 14 минут
Цитата Сообщение от Vissmuy Посмотреть сообщение
у меня в ресурсах приложения в файле App.xaml есть такое вот.
Это называется "Шаблон данных по умолчанию".
Использует его, в данной реализации, ContentControl из MainWindow. Он получает значение из свойства "{Binding CurrentView}" от MainWindow(MainWindowViewModel viewModel). И ищет шаблон по типу. Это вложенное поведение ContentControl.
MainWindowViewModel начальным значением свойства CurrentView задаёт BirdsViewModel.
И здесь принципиальным становится вопрос в каком порядке, что инициализируется.
В первоначальной реализации ServiceProvider должен был быть обязательно инициализирован до первого вызова MainWindowViewModel. Но не во всех сценариях так происходит. Поэтому я jбернул его в try-catch? чтобы в случае исключения уже подсовывать напрямую экземпляр ServiceProvider.

В целом ваша реализация ServiceProvider вызывает много нареканий. В первую очередь по изоляции слоёв.
Каждый слой App, View, ViewModel, Model - это по идее отдельная сборка.
ServiceProvider реализован в слое App. Но ни один из других слоёв не имеет доступа к слою App. И, следовательно, в MainWindowViewModel не может быть вызова App.ServiceProvider.

Структура WPF решения
Структура связей в WPF Решении
Структура WPF+БД решения
Потоки в асинхронном MVVM
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
29.12.2024, 16:17  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
вызывает много нареканий
Понял. Я переделал репозиторий, свой основной проект туда залил, потому как они по структуре уже почти один в один. Оставил ссылку у себя в профиле. Сейчас с ним буду работать и, надеюсь с вашей помощью, смогу
сделать качественное приложение с быстрой работой при нарастающем объеме данных.
Постараюсь побольше гуглить, чтобы не доставать через чур вопросами. Благодарю уже за то, что вы сделали.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
30.12.2024, 00:17
Цитата Сообщение от Vissmuy Посмотреть сообщение
свой основной проект туда залил
Через удаление предыдущего?
Нарушился Fork.
Надо заливать в текущий.
Сейчас придётся пересоздавать свой Fork.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
30.12.2024, 03:44  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Сейчас придётся пересоздавать свой Fork.
Такс, как понять мой Fork? Я в первый раз когда проект обрезанный заливал, ничего подобного не делал.

И из определения нифига не понятно
Форк (Fork) — собственное ответвление (fork) какого-то проекта. Это означает, что GitHub создаст вашу собственную копию проекта, данная копия будет находиться в вашем пространстве имён, и вы сможете легко делать изменения путём отправки (push) изменений.
Может кто на примере подсказать, что все таки такое Fork в GitHub?

Добавлено через 2 минуты
Так, разобрался. Да, придется еще один раз создать эту вилку, но теперь у меня локальный репозиторий в нормальном месте, где все проекты, а не черт пойми где на другом диске.

Добавлено через 1 минуту
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Через удаление предыдущего
Понимаю, что наверняка был способ не удалять тот репо, но пока разобрался бы...
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
30.12.2024, 10:31
Vissmuy, сильно не переживайте.
Я сам не шибко GitHub знаю.
Осваивайте по мере возможностей. Пригодится.

По репу буду отправлять изменения не все сразу. А по шагам с существенными изменениями. Чтобы вы могли уследить за ними и понять их логику.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
30.12.2024, 10:39
Цитата Сообщение от Vissmuy Посмотреть сообщение
Может кто на примере подсказать, что все таки такое Fork в GitHub?
Вот мой Fork вашего Репозитория.
Все Fork-и вы можете посмотреть в своём Репе:


Fork - это вилка, клон. Делается чтобы вносить изменения не затрагивая основной Реп. Синхронизацию от основного в Fork можно делать всегда, обратные изменения из Fork в основной только через "Pull request" после принятия владельцем основного.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
30.12.2024, 18:00
Цитата Сообщение от Vissmuy Посмотреть сообщение
Да, придется еще один раз создать эту вилку,
Если нужно заменить проект не нарушая связи с Fork-ами, то переходите в Студии на нужную ветку, выходите из Студии, удаляете все файлы из локального репа, кроме папки .git, копируете в эту папку файлы нужно проекта, открывает Студию и фиксируете изменения.

Добавлено через 3 часа 36 минут
Отправил запрос на изменения:
Добавлен проект общей библиотеки.
Исправлены зависимости базовых классов.
Изменена реализация сервиса навигатора.
Добавлено через 3 часа 34 минуты
Ещё один Pull request с началом реализации Репозитория.
Пока нет времени дальше продолжать.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
30.12.2024, 18:04  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Пока нет времени дальше продолжать.
Действительно. Стоит чуть чуть притормозить, там уже больше тысячи изменений. Тут просто подготовка к праздникам, также времени нема сейчас. Но спасибо, как оклемаюсь, начну изучать.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
30.12.2024, 18:36
Цитата Сообщение от Vissmuy Посмотреть сообщение
Стоит чуть чуть притормозить, там уже больше тысячи изменений.

В первом Pull request перенос проектов по папкам.
Это порождает много изменений, но среди них почти нет существенных.

Добавлено через 1 минуту
Не подумал об этом.
Следовало сначала сделать перенос. Зафиксировать. И только потом вносить изменения.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
31.12.2024, 05:08  [ТС]
День добрый. С наступающим всех. Есть проблема с StringFormat в Xaml.

XML
1
2
3
4
5
6
<TextBlock Text="{Binding Departure, StringFormat=dd.MM.yyyy}"
           Margin="0 0 20 0"
           Foreground="White"
           FontSize="24"
           VerticalAlignment="Center"
           HorizontalAlignment="Center">
В вышеприведенном коде TextBlock привязан к свойству с типом DateOnly и когда я делаю StringFormat происходит следующее: выводится, как я понял, значение по умолчанию для этого типа данных.

Без StringFormat все норм, значение выводится только когда я свойству присваиваю значение из TextBox под кнопкой, но выводится оно в неудобном формате.

Удалось пофиксить добавлением триггера TextBox'у, который просто скрывает этот TextBlock. Подскажите, такое решение грамотное?
XML
1
2
3
4
5
6
7
8
9
10
11
<TextBlock.Style>
    <Style TargetType="TextBlock">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsActive}"
                         Value="True">
                <Setter Property="Visibility"
                        Value="Collapsed" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</TextBlock.Style>
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
31.12.2024, 10:49  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Ещё один Pull request
Слишком много всего, даже читая комментарии, я не соображаю.
Кстати ObservableObject из проекта BirdsCommon и BaseInpc из того же проекта в папке ViewModelBase одинаковы.

Попробую сначала ознакомиться с примером реализации в вашей теме.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
31.12.2024, 12:31
Цитата Сообщение от Vissmuy Посмотреть сообщение
даже читая комментарии, я не соображаю.
Пошагово буду объяснять.

Step1. Внедрение общей библиотеки.

Взял свои реализации, которые часто использую и добавил проект для них:
  • BaseInpc - базовая реализация INotyfyPropertyChanged;
  • CommandHadlers - делегаты для методов команд;
  • RelayCommand - базовая реализация ICommand. Создаёт команды для методов с параметром типа object, который не надо конвертировать и для методов без параметра;
  • RelayCommand<T> - производный класс команд для методов с типизированным параметром. По умолчанию используется сопостовление с типом оператором is, но можно указать и свой конвертер для преобразования. Особенность применения конвертера, он применяется только если неудачно сопоставление is. Например, для параметра object конвертер никогда не будет вызываться, или для привязки к TextBox.Text к string параметру тоже не будет вызываться. Такое поведение можно настраивать, но в данной реализации посчитал это излишним усложнением;
  • ViewModelBase - класс производный от BaseInpc "продвинутая" реализация упрощающая объявление свойств и команд;
  • CommandExtensionMethods - методы расширения для вызова команд из кода Шарп. Содержат в себе повторяющийся код, уменьшают его дублирование;
  • IClonable<T> - интерфейс клонирования с типизированным клоном, в отличии от системного IClonable который возвращает клон object;
  • CloneHelper - Метод расширения создающий неглубокий клон любого object. Использует метод MemberwiseClone;
  • PropertyDescriptorHelper - методы для работы с PropertyDescriptor. В данном случае они не пригодились. Предназначены для экземпляров у которых нет реализации INPC. У таких объектов при изменении свойств привязки к ним не будут автообновляться. С использованием этих методов для присваивания значения свойствам привязки автообновляться. Также методы для подключения и отключения прослушек изменения свойств. INPC не единственный механизм отслеживания изменений и PropertyDescriptor позволяет учитывать все механизмы используемые привязками;
  • ISyncedList - интерфейс для "продвинутой синхронизации" коллекций в WPF. Использование ReaderWriterLocker позволяет одновременно многим читать и только одному записывать. Блокировка происходит только на время записи. Не используется в этом Решении;
  • SyncedList<T> - список реализующий "продвинутую" синхронизацию. Не используется в этом Решении;
  • SyncedObservableCollection<T> - ObservableCollection с реализацией продвинутой синхронизации. Не используется в этом Решении;

Добавлено через 15 минут
Цитата Сообщение от Vissmuy Посмотреть сообщение
ObservableObject из проекта BirdsCommon и BaseInpc из того же проекта в папке ViewModelBase одинаковы.
ObservableObject - это название файла. 1-й класс в нём BaseInpc. А вот класс ObservableObject в этом же файле уже лишний. Оставлял файл для совместимости при рефакторинге и забыл удалить этот файл.

Отличия в реализациях свойств.
Объявление свойств для вашей первичной реализации ObservableObject:

C#
1
2
3
4
5
6
7
8
9
10
11
12
        private string _someProperty;
        public string SomeProperty
        {
            get => _someProperty;
            set
            {
                if (Equals(_someProperty, value))
                    return;
                _someProperty = value;
                OnPropertyChanged();
            }
        }
Объявление свойства с BaseInpc:
C#
1
2
        private string _someProperty;
        public string SomeProperty { get => _someProperty; set => Set(ref _someProperty, value); }
Объявление свойства с ViewModelBase:
C#
1
        public string SomeProperty { get => Get<string>(); set => Set(value); }
Отличия в реализациях комманд.

Для вашей первичной реализации ObservableObject и BaseInpc:
C#
1
2
        private RelayCommand? _someCommand;
        public RelayCommand SomeCommand => _someCommand ??= new RelayCommand<string>(SomeExecuteMethod);
Для ViewModelBase:
C#
1
        public RelayCommand SomeCommand => GetCommand<string>(SomeExecuteMethod);
Добавлено через 4 минуты
Первый Шаг завершается переводом всех VM на ViewModelBase.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
31.12.2024, 12:56
Step2. Внедрение Репозитория.

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

Для универсальности в общей библиотеке объявлен базовый класс (запись) для сущностей Репозитория в котором есть целый Id.
Создан интерфейс универсального репозитория.
И объявлен класс (запись) Bird. Bird несёт двоякую функцию. При получении от Репозитория - это сущность связанная и отслеживаемая Репозиторием. Менять свойства этих сущностей нельзя - это может повлечь баги в работе Репозитория. При создании Bird вне репозитория -это обычный DTO, который используется как контейнер для передачи значений.

Далее для Репозитория Bird был добавлен новый проект:
  • DbBirdsRepository - сам Репозиторий. Использует единый контекст БД на время своей жизни. Может принимать любой DbContext в котором можно получить DbSet<Bird>. Для обновления БД используются "одноразовые" контексты, поэтому требует делегат метода возвращающего новый контекст. При создании по имени БД используется internal ApplicationDbContext для SQLite. В Репозитории предусмотрен возврат ObservableCollection отражающий локальный кеш единого контекста. Обновления кеша происходит после каждого обновления БД из этого же репозитория. ObservableCollection лучше заменить на ReadOnlyObservableCollection - забыл это сделать. Многопользовательский режим не поддерживается. То есть если изменить БД не из этого Репозитория, то обновления локального кеша не произойдёт;
  • ApplicationDbContext - класс локального контекста для Bird в SQLite. Подключает БД по её полному или относительному стринг имени. В OnConfiguring подключено логирование - его можно убрать;
  • BirdConfiguration - конфигурация БД для Code First. Есть первичная инициализация демо-данными.
Второй Шаг завершается переводом всех VM на получение IRepository<Bird>.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
31.12.2024, 13:12
Step 3. Рефакторинг Моделей Представления.

Все VM перенесены в отдельный проект.

Навигатор совмещён с Основной ViewModel MainBirdsViewModel. Сервисы убраны для получения экземпляров убраны, чтобы упростить понимание связей и их создание.
В MainBirdsViewModel создаются дочерние VM BirdsViewModel и AddBirdViewModel. Все команды для работы с репозиторием объявлены в MainBirdsViewModel.
Не совсем понял что за список BirdNameGroups, но сделал его статическим. В экземпляре для удобства прокси свойство возвращающее этот статический список.
Birds передаёт в View неизменяемый локальный кеш контекста. privateBirds уже не нужен. Надо перенести создание ReadOnlyObservableCollection в Репозиторий.
Добавлена команда навигации по типу VM NavigateToType.

BirdsViewModel - здесь уже никакого функционала практически не осталось. Departure содержащий дату создания экземпляра BirdsViewModel и NumberOfBirds не понял чо это такое. Больше ничего здесь нет.

AddBirdViewModel - вообще, пустой класс. Используется только для переключения Представлений.

Третий Шаг на этом завершается.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
31.12.2024, 13:27
Step 4. Рефакторинг View и App.

Пока разделять View и App не стал - и так хватает сложностей понимания.
Для упрощения конструирование, нужно создавать экземпляры используемые в View на XAML.
Так как создание MainBirdsViewModel требует параметрического конструктора, то для упрощения создал Расширение Разметки MainBirdsViewModelExtension:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using BirdsRepository;
using BirdsViewModels;
using System.Windows.Markup;
 
namespace BirdsWPF
{
    [MarkupExtensionReturnType(typeof(MainBirdsViewModel))]
    public class MainBirdsViewModelExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return new MainBirdsViewModel(new  DbBirdsRepository ("birds.db"));
        }
    }
}
При необходимости можно его дополнить параметром принимающим имя БД или DbContext, но сейчас не стал усложнять.
Экземпляр создаётся в ресурсах App:
XML
19
            <local:MainBirdsViewModel x:Key="mainVM"/>
Это позволяет обращаться к нему из любого места XAML.

MainWindow получает в Контексте Данных этот экземпляр DataContext="{DynamicResource mainVM}" и в основном использует его только для навигации:
XML
57
58
59
60
61
62
63
64
                <RadioButton Content="Add Bird"
                             Height="50"
                             Foreground="White"
                             FontSize="20"
                             Style="{StaticResource MenuButtonTheme}"
                             IsChecked="True"
                             Command="{Binding NavigateToType, Mode=OneWay}"
                             CommandParameter="{x:Type vm:AddBirdViewModel}"/>
Только сейчас увидел, что при старте Окно пустое.
Надо в MainBirdsViewModel добавить установление первоначального текушего значения:
C#
14
15
16
17
        public MainBirdsViewModel(IRepository<Bird> birdsRepository)
        {
            this.birdsRepository = birdsRepository;
            Current = birdsVM = new(birdsRepository);
BirdsView и AddBirdView получают в Контексте Данных свои VM, если нужны общие данные то обращаются в Основной VM. Пример получения команды:
XML
78
79
80
81
82
83
84
85
86
87
88
89
90
        <Button Content="Save the bird"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Margin="0 20 0 0"
                Background="Transparent"
                Foreground="AliceBlue"
                FontSize="24"
                FontWeight="Light"
                Padding="10"
                BorderBrush="Black"
                Command="{Binding AddBirdCommand, Mode=OneWay, Source={StaticResource mainVM}}"
                CommandParameter="{Binding}"
                Style="{StaticResource CSButtons}" />
В BirdsView добавил источник Времени Разработки, чтобы Конструирование было нагляднее:
XML
52
53
54
55
56
57
58
59
60
61
            <ItemsControl ItemsSource="{Binding Birds, Mode=OneWay, Source={StaticResource mainVM}}"
                          Margin="0 0 0 0">
                <d:ItemsControl.ItemsSource>
                    <x:Array Type="rep:Bird">
                        <rep:Bird Name="qwerty"/>
                        <rep:Bird Name="asdfg" IsActive="True"/>
                        <rep:Bird Name="zxcvb"/>
                        <rep:Bird Name="yuiop" IsActive="True"/>
                    </x:Array>
                </d:ItemsControl.ItemsSource>
На этом всё.
Если есть какие-то вопросы по конкретным фрагментам кода, логике - пишите.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
31.12.2024, 13:27

Mvvm ViewModel в ViewModel
Есть одно окошко там много вкладок, в каждой вкладке есть подвкладки и там много разных таблиц и кнопок. ViewModel будет просто огромной,...

Как внедрить БД в exe на VB 6.0
Hi! Есть база на Access 7.0 и проект на VB 6.0. Можно ли как-нибудь всунуть .mdb файл в exe-шник, чтобы никто не мог его открыть и...

Как внедрить функцию
Здравствуйте, есть программа которая считает в edit сколько открывающихся скобок и закрывающихся. мой код выглядит так: procedure...

как с внедрить свой код
Всем привет! Не подскажите как можно создать свою папку в вордпресссом и внедрить свой код. Сейчас есть сайт на вордпресс, там нужно...

Как внедрить ProgressBar в макрос
Добрый день! почитал соседние темки на эту тему, нашел у товарища analyst архив с замечательными формами ProgressBar но так как...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
100
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru