Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468

Приложение MVVM. Быстрая "Нестрогая MVVM" реализация

09.03.2023, 11:49. Показов 2971. Ответов 48
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
В этой теме будет размещена простая и быстрая реализация.
Основная тема: Приложение MVVM. VMs и навигация
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
09.03.2023, 11:49
Ответы с готовыми решениями:

Рисую линию без MVVM все ОК. C MVVM произвольный старт
Добрый день всем. Рисую линию при помощи анимации. Все получилось -рисуется, стирается. Но у нас все задания с MVVM, чтобы ViewModel...

Реализация паттерна MVVM
Добрый день, форумчане. Ни разу не пользовался данным паттерном программирования, прочитал уже кучу статей, но ни одна из них не может мне...

MaterialDesign - Transitions, MVVM реализация
Добрый день! В библиотеке MaterialDesign есть интересная реализация переходов между UserControl (основная разметка в файле...

48
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 11:32  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
C#
1
db.Database.EnsureCreated();
Да, точно, я совсем забыл про вызов этого метода.
Спасибо большое.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
И хоть чуток освойте Entity Framework.
Осваивал и немного умею пользоваться им
Цитата Сообщение от Элд Хасп Посмотреть сообщение
C#
1
public LocalView<Manufacturer> Manufacturers => catalog.Manufacturers.Local;
Так я тоже раньше делал, только после Local дописывал ToObservableCollection

Добавлено через 1 час 22 минуты
C#
1
2
3
4
5
6
private readonly BigViewModel viewModel;
        public AuthorizeView()
        {
            InitializeComponent();
            viewModel = (BigViewModel)DataContext;
        }
Почему-то этот код не хочет корректно работать. DataContext в конструкторе ещё равен null. Поэтому приходится устанавливать контекст в обработчике Loaded, там он уже != null
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 19:46
Цитата Сообщение от INexteR Посмотреть сообщение
DataContext в конструкторе ещё равен null.
Не может быть.
У меня же всё работает.

Сейчас проверю последние ваши фиксации.

Добавлено через 8 минут
Цитата Сообщение от INexteR Посмотреть сообщение
Так я тоже раньше делал, только после Local дописывал ToObservableCollection
ToObservableCollection это метод создающий каждый раз, при каждом обращении разную коллекцию.
Нам нужна максимально простая реализация без всяких выкурутасов.
Поэтому достаточно даже перечисления IEnumerable<T> или коллекции ICollection<T>.

Добавлено через 2 минуты
INexteR, фиксаций с изменениями не скидывали?
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 20:14  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
ToObservableCollection это метод создающий каждый раз
Я тоже так думал. Но оказалось не так
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 20:19
Цитата Сообщение от INexteR Посмотреть сообщение
Я тоже так думал. Но оказалось не так
Что не так?
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 20:21  [ТС]
Я вот сейчас отправил новую фиксацию. Да, посмотрите.
И тут я такую реализацию фильтрации с поиском придумал. Она неэффективна? Вот код
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private void Search_TextChanged(object sender, TextChangedEventArgs e)
{
    source.Filter -= ftr;
    if (!string.IsNullOrWhiteSpace(search.Text))
    {
        if (IsFilterNotContains(NameSearch))
            ftr += NameSearch;
    }
    else
        ftr -= NameSearch;
    source.Filter += ftr;
}
 
private void Filter_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    source.Filter -= ftr;
    if (filter.SelectedIndex != 0)
    {
        if (IsFilterNotContains(ManufacturerFilter))
            ftr += ManufacturerFilter;
    }
    else
        ftr -= ManufacturerFilter;
    source.Filter += ftr;
}
 
private bool IsFilterNotContains(FilterEventHandler filter)
{
    return ftr is null || !ftr.GetInvocationList().Contains(filter);
}
 
private FilterEventHandler? ftr;
 
private void NameSearch(object sender, FilterEventArgs e)
{
    if (!((Product)e.Item).Name.Contains(search.Text))
        e.Accepted = false;
}
private void ManufacturerFilter(object sender, FilterEventArgs e)
{
    if (((Product)e.Item).Manufacturer != Manufacturer)
        e.Accepted = false;
}
 
private Manufacturer? Manufacturer => filter.SelectedItem as Manufacturer;
Добавлено через 30 секунд
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Что не так?
Коллекция одна и та же возвращается

Добавлено через 1 минуту
search и filter это соответственно строка поиска и список выбора
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 20:23
INexteR, посмотрел исходники - вы правы:
C#
92
93
94
95
96
97
98
99
100
101
102
    public virtual ObservableCollection<TEntity> ToObservableCollection()
    {
        if (_observable == null)
        {
            _observable = new ObservableCollection<TEntity>(this);
            _observable.CollectionChanged += ObservableCollectionChanged;
            CollectionChanged += LocalViewCollectionChanged;
        }
 
        return _observable;
    }
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 20:25  [ТС]
Я, кстати, уже написал сегодня вариант. Так что эту тему можно пока отложить
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 20:27
Цитата Сообщение от INexteR Посмотреть сообщение
И тут я такую реализацию фильтрации с поиском придумал. Она неэффективна? Вот код
Попробуйте сами проанализировать и сравнить с другими реализациями.
Напишите что у вас вышло - потом обсудим.

Добавлено через 35 секунд
Цитата Сообщение от INexteR Посмотреть сообщение
Я, кстати, уже написал сегодня вариант.
В смысле экзамен (или тест)?
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 20:31  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
INexteR, посмотрел исходники - вы правы:
Я просто проверял это программно)) Сначала вызвал этот метод и подписался на CollectionChanged. Далее обратился снова к этому методу и попробовал удалить элемент. Сработал обработчик события

Добавлено через 2 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В смысле экзамен (или тест)?
Ну это был пробный экзамен. Настоящий будет в июне
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 20:32
INexteR, есть свои нюансы: Совет
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 20:56  [ТС]
Элд Хасп, я успел сделать
Цитата Сообщение от INexteR Посмотреть сообщение
авторизацию, каталог, вывод в нем, поиск (одно поле на несколько свойств), сортировку и фильтрацию. Ну и ещё дополнения в виде отображения кол-ва записей, возврата на авторизацию. И удаление
Надо будет ещё как-то научиться успевать делать добавление и редактирование

Добавлено через 4 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Попробуйте сами проанализировать и сравнить с другими реализациями.
Напишите что у вас вышло - потом обсудим.
По-моему неэффективно. Там я использую метод GetInvocationList для просмотра очереди вызовов. Меня это смущает, наверное это долгий метод. А как проанализировать?

Добавлено через 2 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Цитата Сообщение от INexteR Посмотреть сообщение
DataContext в конструкторе ещё равен null.
Не может быть.
У меня же всё работает.
Ну действительно так было почему-то. Сейчас снова проверю

Добавлено через 9 минут
Теперь контекст уже есть в конструкторе... Но вот ресурс CollectionViewSource не находится :/

Добавлено через 3 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Когда закончите перенос всего необходимого, то создадите ветку и уже в ней удалите не нужное Решение.
Не могу понять. Ненужное решение переместить в другую ветку что ли?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 21:13
INexteR, для нас это избыточно, в любом случае.
Цитата Сообщение от INexteR Посмотреть сообщение
Не могу понять. Ненужное решение переместить в другую ветку что ли?
Нет. Просто удалите и сделайте фиксацию в нужной ветке.
В другой останется всё по прежненму.

Добавлено через 40 секунд
Цитата Сообщение от INexteR Посмотреть сообщение
Надо будет ещё как-то научиться успевать делать добавление и редактирование
Тогда продолжим "скоростной".
Доведём сначала его до конца.
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 21:25  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Тогда продолжим "скоростной".
Доведём сначала его до конца.
Я так понимаю, представленный в этой теме? Если так, то нееет, давайте сначала ту тему закончим. Мне теперь то нужно скорее сдать
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 21:33
C#
57
58
59
60
61
62
63
64
    public static class WinHelper
    {
        public static void Navigate<TNewView>(this DependencyObject oldView)
            where TNewView : new()
        {
            Window.GetWindow(oldView).Content = new TNewView();
        }
    }
Добавлено через 52 секунды
Цитата Сообщение от INexteR Посмотреть сообщение
Мне теперь то нужно скорее сдать
Ок.
Тогда там пишите, на чём остановились.
Я пока ветки разделю.
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 21:42  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
А если будете переключать ветки, то одновременно будете видеть только одно Решение.
Ну смотрите. Здесь у меня 2 решения и они открыты в разных окнах. Притом они в одной ветке. А могло бы быть 2 решения в разных окнах и в разных ветках. Какая разница? Мне даже второе кажется лучше. Изначально я подумал, что Вы предложили 1 вариант по той причине, что это было бы в одном окне

Добавлено через 3 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Я пока ветки разделю.
Эммм. Что-то вообще не понимаю

Добавлено через 47 секунд
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Тогда там пишите, на чём остановились.
Это будет завтра
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 21:48
Цитата Сообщение от INexteR Посмотреть сообщение
вообще не понимаю
Сделайте локальный репозиторий - ветка main.
В него добавьте любой файл (картинку например).
Сделайте локальную фиксацию.
Создайте новую ветку в этом репозитории - века First.
Добавьте в него ещё один файла и сделайте фиксацию.
Перейдите в ветку main - там не будет второго файла.
Создайте ещё ветку Second, добавьте неё ещё файл и сделайте фиксацию.

Теперь при переключении веток у вас будут разные файлы в папке - проверьте проводником.
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
10.03.2023, 21:58  [ТС]
Элд Хасп, а вот это
Цитата Сообщение от INexteR Посмотреть сообщение
Ну смотрите. Здесь у меня 2 решения и они открыты в разных окнах. Притом они в одной ветке. А могло бы быть 2 решения в разных окнах и в разных ветках. Какая разница? Мне даже второе кажется лучше. Изначально я подумал, что Вы предложили 1 вариант по той причине, что это было бы в одном окне
Добавлено через 47 секунд
Ну да... тут ещё репозиторий надо конкретно изучать
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
10.03.2023, 23:29
C#
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        public void Init(bool recreate = false)
        {
            if (recreate)
            {
                if (File.Exists(dataBaseName))
                    File.Delete(dataBaseName);
            }
            catalog.Database.EnsureCreated();
 
            // Если все сущности загружаются, то не нужно делать Include()
            catalog.Roles.Load();
            catalog.Categories.Load();
            catalog.Manufacturers.Load();
            catalog.Suppliers.Load();
            catalog.Units.Load();
            catalog.Users.Load();
            catalog.Products.Load();
            catalog.OrderStatuses.Load();
            catalog.PickupPoints.Load();
            catalog.Orders.Load();
            catalog.OrderProducts.Load();
        }
0
 Аватар для INexteR
17 / 16 / 1
Регистрация: 25.01.2023
Сообщений: 468
11.03.2023, 07:29  [ТС]
Элд Хасп, а на цитируемое сообщение выше можете ответить? Я не понял, в чем предмет удобства. Или Вы уже ответили на этот вопрос? Мне просто показалось, что не на него Вы отвечали
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
11.03.2023, 09:05
INexteR, о ветках репозитория?
Если да, то:
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Сделайте локальный репозиторий - ветка main.
В него добавьте любой файл (картинку например).
Сделайте локальную фиксацию.
Создайте новую ветку в этом репозитории - века First.
Добавьте в него ещё один файла и сделайте фиксацию.
Перейдите в ветку main - там не будет второго файла.
Создайте ещё ветку Second, добавьте неё ещё файл и сделайте фиксацию.
Теперь при переключении веток у вас будут разные файлы в папке - проверьте проводником.
Не получится одновременно открыть две ветки в одном репозитории.
Для этого нужно делать два РАЗНЫХ локальных клона репозитория в каждом из которых своя отрытая ветка.

Сейчас я разделил Решения по проектам.
Попробуйте открыть в последней фиксации одновременно решения NewTrade (ветка Trial) и Demo (ветка FastMvvm).

Добавлено через 58 минут
Цитата Сообщение от INexteR Посмотреть сообщение
По-моему неэффективно. Там я использую метод GetInvocationList для просмотра очереди вызовов. Меня это смущает, наверное это долгий метод. А как проанализировать?
Как вы представляете реализацию мультиделегата, добавления в него делегата и вызов его на исполнение?
Это просто инкапсулированный массив. И каждый ftr += ...; добавляет элемент в этот массив.
При вызове мултиделегата, происходит обычный цикл по элементам этого массива и вызывается последовательно каждый делегат (более точно - метод на который ссылается делегат).
Вызов метода - "дорогая" операция. В каждом методе производит явное приведение элемента (Product)e.Item), что тоже является "дорогой" операцией.
В каждом методе вы извлекаете заново значение DependencyProperty search.Text, что тоже является дорогой операцией.
О самой реализации присвоение булевого значения через отрицания в if блоке.... Без обид - это "ниже плинтуса".


Другое дело, что на фоне издержек WPF дороговизна всего этого не существенна. Но тем не менее если говорить об эффективности по скорости, то разница с моноделегатом будет в разы.

Так же не очевиден сам код, он трудно читается. Что-то куда-то добавляется, декапсулируется делегат. Стороннему разработчику в такую мешанину трудно вникать. А ООП это не про то "как мне удобно", а про коллективное программирование. В ОПП нужно создавать код, который легко читается другими разработчиками.


Сравните с такой реализацией:
C#
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
        private string? searchText;
        private object searchManufacturer =  ViewsHelper.AllManufacturers;
        public string? SearchText
        {
            get => searchText;
            set { searchText = value; SearchChanged(value?.Trim(), SearchManufacturer as Manufacturer); }
        }
        public object SearchManufacturer
        {
            get => searchManufacturer;
            set { searchManufacturer = value ?? ViewsHelper.AllManufacturers; SearchChanged(SearchText?.Trim(), value as Manufacturer); }
        }
 
        private FilterEventHandler? filter;
        private void SearchChanged(string? text, Manufacturer? manufacturer)
        {
            source.Filter -= filter;
 
            filter = (string.IsNullOrEmpty(text), manufacturer == null) switch
            {
                (false, false) => (s, e) => NameManufacturerSearch(s, e, text!, manufacturer!),
                (false, true) => (s, e) => NameSearch(s, e, text!),
                (true, false) => (s, e) => ManufacturerSearch(s, e, manufacturer!),
                _ => null,
            };
 
            source.Filter += filter;
        }
 
        private static void NameSearch(object sender, FilterEventArgs e, string name)
        {
            e.Accepted = ((Product)e.Item).Name.Contains(name);
        }
        private static void ManufacturerSearch(object sender, FilterEventArgs e, Manufacturer manufacturer)
        {
            e.Accepted = ((Product)e.Item).Manufacturer == manufacturer;
        }
        private static void NameManufacturerSearch(object sender, FilterEventArgs e, string name, Manufacturer manufacturer)
        {
            Product product = (Product)e.Item;
            e.Accepted = product.Manufacturer == manufacturer &&
                         product.Name.Contains(name);
        }
XML
179
180
181
182
183
    <TextBox Grid.Row="1"
                VerticalAlignment="Center"
                Text="{Binding SearchText,
                            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProductsView}},
                            UpdateSourceTrigger=PropertyChanged}"/>
XML
220
221
222
223
224
225
    <ComboBox VerticalAlignment="Center"
                SelectedIndex="0"
                DisplayMemberPath="Name"
                Grid.Row="1"
                SelectedItem="{Binding SearchManufacturer,
                                        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProductsView}}}">
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
11.03.2023, 09:05

Корректна ли такая реализация паттерна MVVM?
Данные из формы не вводятся,а используются для отображения состояния. Программа подобна лабораторному стенду.

Реализация авторизации/регистрации через MVVM
Кто-то может покидать ссылок на реализацию регистрации и авторизации через mvvm (везде только cb), буду благодарен. (wpf).

Реализация ComboBox MVVM свойство selectionchanged
Здравствуйте! Подскажите, пожалуйста, как реализовать ComboBox в рамках MVVM, а именно, как отловить свойство SelectionChanged? View: ...

[WPF] Реализация openFileDialog в соответствии с MVVM
Здравствуйте! Подскажите как должна быть правильно реализована возможность чтения файлов с помощью OpenFileDialog в соответствии с MVVM?...

Реализация master-detail с использованием MVVM
Привет. Интересует вопрос реализации данного интерфейса при помощи MVVM. Есть модель Client, сырые данные получаю через WCF-сервис...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Nekobox - outbounds[0].transport: unknown transport type: raw
damix 01.10.2026
Фикс ошибки Правым кликом по серверу -> отладочная информация -> edit Заменить "net": "raw", на "net": "tcp", Нажать кнопку reload.
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru