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

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

26.12.2024, 11:19. Показов 27498. Ответов 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
24.02.2025, 16:20  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это уже вас уже другой проект, не Birds?
Ну хорошо. Я и до этого старался говорить в контексте проекта по птицам. Допустим, у нас во View в проекте по птицам есть тогл кнопка, ее состояние должно быть отправлено в другую вью для соответствующих действий. Как бы вы поступили в подобной ситуации?

Добавлено через 31 минуту
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
А если использовать событие?
Честно я пока с событиями не дружу и не понимаю, как там кто-то кого-то слушает. Нужно будет закрыть этот пробел.

Цитата Сообщение от Andrey-MSK Посмотреть сообщение
Во View
Также я пока не знаю что можно запихивать в секцию cb в mvvm, а что нежелательно.

Добавлено через 4 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Почти на 100% уверен, что путаница в экземплярах VM.
При объявлении ViewModel в ресурсах UserControl она создается новая? Если да, тогда понятно в чем дело.
0
 Аватар для Andrey-MSK
3397 / 2283 / 388
Регистрация: 14.08.2018
Сообщений: 7,765
Записей в блоге: 4
24.02.2025, 16:59
Цитата Сообщение от Vissmuy Посмотреть сообщение
Также я пока не знаю что можно запихивать в секцию cb в mvvm, а что нежелательно.
В CB можно писать логику которая относится к View. То что касается элементов UI, их поведение, анимации, управление CollectionViewSource и т.д. Вот пример
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
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Data;
 
using DBClient.Services.Sorters;
 
using Services.Interfaces.WindowsVM;
 
namespace DBClient.Views.Windows
{
    /// <summary>
    /// Interaction logic for PPWorkHBWindow.xaml
    /// </summary>
    public partial class PPWorkHBWindow : Window
    {
        // Поля класса View для управления CollectionViewSource
        private CollectionViewSource _sourcePPGrops;
        private CollectionViewSource _sourcePPWorks;
        private CollectionViewSource _sourceHBTypes;
        private CollectionViewSource _sourceHBWorks;
 
        private ListCollectionView _viewPPGroups;
        private ListCollectionView _viewPPWorks;
        private ListCollectionView _viewHBTypes;
        private ListCollectionView _viewHBWorks;
 
        public PPWorkHBWindow()
        {
            InitializeComponent();
        }
 
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Получаем ссылку на VM из DataContext
            IPPWorkHBWindowVM vm = (IPPWorkHBWindowVM)DataContext;
 
            // Получаем экземпляры CVS из ресурсов окна
            _sourcePPGrops = (CollectionViewSource)Resources["PPGroupsSort"];
            _viewPPGroups = (ListCollectionView)_sourcePPGrops.View;
 
            _sourcePPWorks = (CollectionViewSource)Resources["PPWorksSort"];
            _viewPPWorks = (ListCollectionView)_sourcePPWorks.View;
 
            _sourceHBTypes = (CollectionViewSource)Resources["TypesSort"];
            _viewHBTypes = (ListCollectionView)_sourceHBTypes.View;
 
            _sourceHBWorks = (CollectionViewSource)Resources["WorksSort"];
            _viewHBWorks = (ListCollectionView)_sourceHBWorks.View;
 
            // Устанавливаем самописный сортировщик для коллекции
            _viewPPWorks.CustomSort = PPWorkHBSorter.Instance;
 
            // Подписываемся на события VM
            vm.PPGroupsLoaded += OnPPGroupsLoaded;
            vm.PPWorksLoaded += OnPPWorksLoaded;
            vm.LaborHBTypesLoaded += OnLaborHBTypesLoaded;
            vm.LaborHBWorksLoaded += OnLaborHBWorksLoaded;
 
            vm.ViewContext = SynchronizationContext.Current;
        }
 
        private void Window_Closing(object sender, CancelEventArgs e)
        {
            IPPWorkHBWindowVM vm = (IPPWorkHBWindowVM)DataContext;
 
            // Отписываемся от событий VM
            vm.PPGroupsLoaded -= OnPPGroupsLoaded;
            vm.PPWorksLoaded -= OnPPWorksLoaded;
            vm.LaborHBTypesLoaded -= OnLaborHBTypesLoaded;
            vm.LaborHBWorksLoaded -= OnLaborHBWorksLoaded;
        }
 
        // Манипулируем выделением первого элемента CollectionViewSource с сортировкой
        private void OnPPGroupsLoaded(object sender, EventArgs e)
        {
            if (_viewPPGroups.Count > 0)
                _ = _sourcePPGrops.View.MoveCurrentToFirst();
        }
 
        private void OnPPWorksLoaded(object sender, EventArgs e)
        {
            if (_viewPPWorks.Count > 0)
                _ = _sourcePPWorks.View.MoveCurrentToFirst();
        }
 
        private void OnLaborHBWorksLoaded(object sender, EventArgs e)
        {
            if (_viewHBWorks.Count > 0)
                _ = _sourceHBWorks.View.MoveCurrentToFirst();
        }
 
        private void OnLaborHBTypesLoaded(object sender, EventArgs e)
        {
            if (_viewHBTypes.Count > 0)
                _ = _sourceHBTypes.View.MoveCurrentToFirst();
        }
    }
}
Добавлено через 2 минуты
Vissmuy, Вот ресурсы окна из примера
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<Window.Resources>
    <CollectionViewSource Source="{Binding PPGroups}" x:Key="PPGroupsSort">
        <CollectionViewSource.SortDescriptions>
            <cvs:SortDescription PropertyName="GroupName"/>
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
    <CollectionViewSource Source="{Binding PPWorks}" x:Key="PPWorksSort"/>
    <CollectionViewSource Source="{Binding LaborHBTypes}" x:Key="TypesSort">
        <CollectionViewSource.SortDescriptions>
            <cvs:SortDescription PropertyName="PosNumber"/>
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
    <CollectionViewSource Source="{Binding LaborHBWorks}" x:Key="WorksSort">
        <CollectionViewSource.SortDescriptions>
            <cvs:SortDescription PropertyName="PosNumber"/>
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
</Window.Resources>
Добавлено через 3 минуты
Vissmuy, Или вот такое ещё. От свойства VM управляем элементами 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
27
28
29
30
31
32
33
34
35
36
using System.Threading;
using System.Windows;
 
using Services.Interfaces.DialogsVM;
 
namespace DBClient.Views.Dialogs
{
    /// <summary>
    /// Interaction logic for CPSContractSelectDialog.xaml
    /// </summary>
    public partial class CPSContractSelectDialog : Window
    {
        public CPSContractSelectDialog()
        {
            InitializeComponent();
        }
 
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ICPSContractSelectDialogVM vm = (ICPSContractSelectDialogVM)DataContext;
 
            vm.ViewContext = SynchronizationContext.Current;
 
            if (vm.CPSEditMode == false)
            {
                btnAdd.Visibility = Visibility.Collapsed;
                btnEdit.Visibility = Visibility.Collapsed;
                btnDelete.Visibility = Visibility.Collapsed;
 
                btnSelect.Content = "Выбрать";
            }
 
            vm.IsLoaded = true;
        }
    }
}
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
24.02.2025, 17:53  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это уже вас уже другой проект, не Birds?
Лучше дайте его через GitHub - так проще будет разобраться.
В целом проект с птицами уже выполняет нужный функционал.
https://github.com/Londongrad/Flashcards-3.0
Вот проект, над которым я сейчас пыхчу. В главной модели отметил основные задачи на текущий момент.

Добавлено через 1 минуту
Цитата Сообщение от Andrey-MSK Посмотреть сообщение
В CB можно писать логику которая относится к View. То что касается элементов UI, их поведение, анимации, управление CollectionViewSource и т.д. Вот пример
Ну так а события, например, клик по кнопке не относятся к поведению UI элемента?
Почему тогда через них не делать все, что угодно?
0
 Аватар для Andrey-MSK
3397 / 2283 / 388
Регистрация: 14.08.2018
Сообщений: 7,765
Записей в блоге: 4
24.02.2025, 17:58
Цитата Сообщение от Vissmuy Посмотреть сообщение
Ну так а события, например, клик по кнопке не относятся к поведению UI элемента?
Почему тогда через них не делать все, что угодно?
Потому что кнопка привязана к команде VM. Если команды нет (нет связи элемента с VM), то можете делать с UI в этом обработчике события что хотите.

Добавлено через 17 секунд
Цитата Сообщение от Vissmuy Посмотреть сообщение
Ну так а события, например, клик по кнопке не относятся к поведению UI элемента?
Почему тогда через них не делать все, что угодно?
Потому что кнопка привязана к команде VM. Если команды нет (нет связи элемента с VM), то можете делать с UI в этом обработчике события что хотите.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
24.02.2025, 22:12
Цитата Сообщение от Vissmuy Посмотреть сообщение
При объявлении ViewModel в ресурсах UserControl она создается новая? Если да, тогда понятно в чем дело.
Тег Хамл с именем типа, всегда создаёт новый экземпляр.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- новый экземпляр. 2 варианта-->
<Имя_Типа/> 
<Имя_Типа>
  
<Имя_Типа/>
 
 
<!-- Вложенный тег с точкой - это задание значения свойству -->
<Имя_Типа>
    <Имя_Типа.Имя_Свойства>
        <!-- Значение свойства -->
    </Имя_Типа.Имя_Свойства>
<Имя_Типа/>
Объектные элементы XAML.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
24.02.2025, 22:16
Цитата Сообщение от Vissmuy Посмотреть сообщение
Допустим, у нас во View в проекте по птицам есть тогл кнопка, ее состояние должно быть отправлено в другую вью для соответствующих действий. Как бы вы поступили в подобной ситуации?
Смотря какие действия.
С большой вероятностью, раз это взаимодействие между двум разными View и их ViewModel, это взаимодействие более высокого уровня. Так же имеет значение функционал этого действия. Это может быть как функционал VM (то есть отражаемый в Модели), тогда это реализуется на уровне Основной VM. Или View - тогда это реализуется на уровне Окна или App.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
25.02.2025, 08:50  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Смотря какие действия.
От состояния кнопки зависит видимость некоторых элементов View.

Добавлено через 3 часа 43 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Тег Хамл с именем типа, всегда создаёт новый экземпляр.
В ресурсах App есть главная модель, в ней есть нужная vm, как тогда обратиться к ней?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
25.02.2025, 09:48
Цитата Сообщение от Vissmuy Посмотреть сообщение
От состояния кнопки зависит видимость некоторых элементов View.
Тогда явной необходимости прокидывать состояния кнопки в ViewModel нет.

Цитата Сообщение от Vissmuy Посмотреть сообщение
В ресурсах App есть главная модель, в ней есть нужная vm, как тогда обратиться к ней?
В данной реализации MainVM выполняет ещё функции Навигатора и Локатора.
Если какой-то дочерний экземпляр VM нужен для постоянного доступа, то кроме предоставления его через Навигатор Current, можно его предоставить и через дополнительное свойство MainVM.

То есть:
C#
11
12
13
14
15
        // Вот это поле, например:
        private readonly BirdsViewModel birdsVM;
 
        // Заменить на такое свойство.
        public BirdsViewModel BirdsVM {get;}
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
25.02.2025, 11:02  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если какой-то дочерний экземпляр VM нужен для постоянного доступа, то кроме предоставления его через Навигатор Current, можно его предоставить и через дополнительное свойство MainVM.
Я так и понял, что через свойства. Но как мне обратиться к этому свойству?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Тогда явной необходимости прокидывать состояния кнопки в ViewModel нет.
Как тогда?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
25.02.2025, 12:17
Цитата Сообщение от Vissmuy Посмотреть сообщение
Но как мне обратиться к этому свойству?
{Binding BirdsVM.Свойство, Source={StaticResource mainVM}}

Цитата Сообщение от Vissmuy Посмотреть сообщение
Как тогда?
Пример подобного класса TextFilterHelper:
C#
1
2
3
4
    public class TextFilterHelper
    {
        public string? Text { get; set; }
    }
Его использование в App:
XML
52
53
54
55
56
57
58
59
60
61
62
            <viewclasses:TextFilterHelper x:Key="textFilter"/>
            <viewclasses:BirdsViewSource x:Key="birds"
                                         Source="{Binding Birds, Source={StaticResource mainVM}}"
                                         TextFilter="{Binding Text, Source={StaticResource textFilter}}"
                                         IsLiveSortingRequested="True">
                <CollectionViewSource.SortDescriptions>
                    <componentmodel:SortDescription PropertyName="IsActive" Direction="Descending"/>
                    <componentmodel:SortDescription PropertyName="Arrival" Direction="Descending"/>
                    <componentmodel:SortDescription PropertyName="Name" Direction="Descending"/>
                </CollectionViewSource.SortDescriptions>
            </viewclasses:BirdsViewSource>
Можете создать общий хелпер или для кнопки отдельный свой класс.
Так как в таких классах значения меняются только из Биндинга, то достаточно простых автосвойств.
Если потребуется изменять значения из Шарпа, то нужна уже полная реализация свойств как для VM.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
26.02.2025, 12:20  [ТС]
Элд Хасп,
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Можете создать общий хелпер или для кнопки отдельный свой класс.
В чем разница между созданием класса чисто для кнопки и тем, чтобы во ViewModel сделать свойство для этой же кнопки?

Элд Хасп, также хотел спросить, вот имею я доступ к CurrentItem из CollectionView. Но могу ли я взять номер этот айтема? Имею ввиду, на каком по счету я сейчас элементе в коллекции
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
26.02.2025, 12:42
Цитата Сообщение от Vissmuy Посмотреть сообщение
В чем разница между созданием класса чисто для кнопки и тем, чтобы во ViewModel сделать свойство для этой же кнопки?
Уровни реализации.

VM отражает Модель. В "абсолюте":
- Эта кнопка изменяет состояние Модели?
- Скорее всего, нет.
- А раз состояние Модели не меняется, то причём здесь ViewModel?

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

Цитата Сообщение от Vissmuy Посмотреть сообщение
Но могу ли я взять номер этот айтема? Имею ввиду, на каком по счету я сейчас элементе в коллекции
В общем виде такого индекса не существует, так как на каждый элемент действует индивидуально Фильтр, Сортировка и Группировка.
Индекс можно получить в представлении этой коллекции.
Я вам показывал вариант с Hidden ListBox.

Добавлено через 3 минуты
Файл BirdsWpfSln/BirdsWPF/Views/UserControls/ListBirdView.xaml в комите efb2018

XML
15
16
17
    <Grid>
        <ListBox Name="listBirds" ItemsSource="{Binding Mode=OneWay, Source={StaticResource birds}}"
                 Visibility="Hidden"/>
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
27.02.2025, 05:06  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Файл BirdsWpfSln/BirdsWPF/Views/UserControls/ListBirdView.xaml в комите efb2018
Я посмотрел, но все еще не понимаю, как я могу решить свою проблему.

И в чем разница между Content="{Binding SelectedItem}, как в комите и Content="{Binding CurrentItem} как сейчас?

Добавлено через 10 минут
Хочу сделать некую валидацию для поля, необходимо проверять - есть ли запись с уникальным свойством в бд, и если есть, то необходимо повлиять на некоторые элементы View, например поменять Visibility одного элемента и отключить кнопку для сохранения записи в бд.

Как лучше это сделать? Раньше я в сеттере свойства для поля, куда ввожу данные, через if вызывал метод для проверки и менял bool переменную, от которой зависело Visibility свойство.

Возможно по совету Andrey-MSK я мог бы в кодовой части представления через DataContext ViewModel получить состояние булевой переменной и оттуда менять свойство UI элемента, но куда и как расположить метод или команду по самой валидации поля, куда я ввожу данные?

Хотя опять же вы(Элд Хасп) говорили, что лучше bool свойство для CheckBox вынести в отдельный класс-хелпер, как тогда иметь к нему доступ?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
27.02.2025, 12:21
Цитата Сообщение от Vissmuy Посмотреть сообщение
И в чем разница между Content="{Binding SelectedItem}, как в комите и Content="{Binding CurrentItem} как сейчас?
SelectedItem - это свойство Selector (от него происходят ListBox, ListViw, DataGrid). У Selector есть свойство SelectedIndex, которое и даёт нужный вам индекс по CollectionView, которую можно получить в свойстве Items. В данном случает она же получается и из ItemsSource, но в общем случае это не всегда так.

А CurrentItem - это свойство CollectionView. А в CollectionView нет индексации.

Цитата Сообщение от Vissmuy Посмотреть сообщение
Хочу сделать некую валидацию для поля, необходимо проверять - есть ли запись с уникальным свойством в бд, и если есть, то необходимо повлиять на некоторые элементы View, например поменять Visibility одного элемента и отключить кнопку для сохранения записи в бд.
Так как это проверка через БД, то реализовываться должна на уровне VM и Model (Репозитория в данном случае).
Если надо просто отключать кнопку, то проще всего добавить проверку в метод CanExecute команды.
Если нужна универсальная проверка, которую можно использовать "где угодно", то на вскидку приходят в голову два варианта:
1) Реализация интерфейса INotifyDataErrorInfo, и потом использование ошибки валидации для включения-выключения нужных элементов;
2) Добавление дополнительных свойств сообщающих о корректности нужных свойств. Что-то по типу:
C#
1
2
3
4
5
6
7
8
9
10
11
public string Name { .....}
public NameIsCorrect { get ...; private set ....}
 
        protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue)
        {
            base.OnPropertyChanged(propertyName, oldValue, newValue);
 
            // Проверяется имя изменившегося свойства и производятся необходимые действия
            if (propertyName == nameof(Name))
                NameIsCorrect = .... ;
        }
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
27.02.2025, 17:12  [ТС]
Элд Хасп, такс, получилось следующее:

Во View, где мне собственно и надо было выводить все это я в ресурсах определяю CollectionViewSource, так как мне по сути эта коллекция только тут и нужна. По крайней мере пока что.
XML
1
2
3
4
<UserControl.Resources>
    <CollectionViewSource x:Key="words"
                          Source="{Binding Words}" />
</UserControl.Resources>
Далее я сделал ListBox по вашему совету, который ссылается на эту коллекцию. Честно говоря, как то муторно все это выглядит. Сначала одна ссылка на коллекцию, тут еще одна ссылка на коллекцию, которая ссылается на коллекцию, но да ладно.
XML
1
2
3
<ListBox Name="ListBox"
         ItemsSource="{Binding Mode=OneWay, Source={StaticResource words}}"
         Visibility="Hidden" />
В нужный TextBlock вывожу данные.
XML
1
2
3
4
5
6
7
<TextBlock Grid.Column="1"
           Style="{StaticResource TextBlock}"
           Margin="0">
    <Run Text="{Binding SelectedIndex, ElementName=ListBox}" />
    <Run Text="/" />
    <Run Text="{Binding Count, Mode=OneWay, Source={StaticResource words}}" />
</TextBlock>
Результат почти нужный: проблема в том, что счет с нуля идет. И при достижении последнего элемента получается 3/4, хотя должно быть 4/4.
Название: изображение_2025-02-27_231152958.png
Просмотров: 103

Размер: 1.1 Кб
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
27.02.2025, 17:23  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Так как это проверка через БД, то реализовываться должна на уровне VM и Model (Репозитория в данном случае).
Вот тоже вопрос есть. Если, к примеру, у меня два репа, но мне метод нужен только для одного? Должен ли я в интерфейсе задать этот метод и там, где этот метод не нужен просто не делать реализацию (Аля throw NotImplemented, все равно же метод вызываться не будет)? Или определить метод только для нужного репа, но как тогда быть с интерфейсом, ведь у него такого метода не будет?

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если нужна универсальная проверка, которую можно использовать "где угодно", то на вскидку приходят в голову два варианта:
Честно говоря, пока не хотелось бы усложнять. На данный момент моя цель - добиться для приложения такого же функционала, как сделал я, но более грамотными методами, а дальше уже можно будет думать над доработками.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
27.02.2025, 23:05
Цитата Сообщение от 2033 Посмотреть сообщение
Результат почти нужный: проблема в том, что счет с нуля идет. И при достижении последнего элемента получается 3/4, хотя должно быть 4/4.
Индексы считаются с нуля.
С этим ничего не поделаешь.
Если нужно с единицы, то надо использовать конвертер инкримента.
Или общее-арифмитический. Пример такого конвертера: ExpressionConverter

Цитата Сообщение от 2033 Посмотреть сообщение
Вот тоже вопрос есть. Если, к примеру, у меня два репа, но мне метод нужен только для одного? Должен ли я в интерфейсе задать этот метод и там, где этот метод не нужен просто не делать реализацию (Аля throw NotImplemented, все равно же метод вызываться не будет)? Или определить метод только для нужного репа, но как тогда быть с интерфейсом, ведь у него такого метода не будет?
Общего ответа нет.

Различные варианты реализации:
1) Производный интерфейс с дополнительным членом;
2) Дополнительный интерфейс для валидации, в том числе INotifyDataErrorInfo;
3) Отдельная модель валидации;
4) Общий интерфейс "на все случаи жизни", но в котором не всегда все члены реализуются. Не реализованное свойство это не обязательно выкидывание исключение при обращении к члену. Это может быть и реализация по умолчанию. Например, в командах в которые передаются только метод Execute, используют для CanExecute метод всегда возвращающий true.


Цитата Сообщение от 2033 Посмотреть сообщение
На данный момент моя цель - добиться для приложения такого же функционала, как сделал я, но более грамотными методами, а дальше уже можно будет думать над доработками.
Тогда выбирайте способ, который пока вам легче реализовать, который проще для понимая, лучше укладывается в голове.
Когда столкнётесь с его ограничения, там уже будете разбирать другие варианты.

Добавлено через 4 минуты
Цитата Сообщение от 2033 Посмотреть сообщение
Во View, где мне собственно и надо было выводить все это я в ресурсах определяю CollectionViewSource, так как мне по сути эта коллекция только тут и нужна. По крайней мере пока что.
Если вам нужна только одна привязка к CollectionViewSource x:Key="words", то нет нужды в использовании экземпляра CollectionViewSource.
ListBox.Items тоже предоставляет экземпляр CollectionView. Все настройки по фильтрации, сортировке и группировке можно производить и с Items.

В моём примере экземпляр CollectionViewSource использовался для того чтобы доступ к нему был из разных страниц View.
0
 Аватар для 2033
4 / 4 / 1
Регистрация: 26.12.2024
Сообщений: 225
19.03.2025, 07:01  [ТС]
Элд Хасп, сейчас сессия, диплом и прочее. Поэтому немного тормознул, хотя все еще интересно освоить wpf.

Поглядывая в перерывах увидел тут в ветке twoentity в репе метод по возвращению данных, который включает в себя проекцию. Для чего здесь проецирование данных? Если убрать - работает также, по крайней мере мне так кажется.

У вас так.
C#
1
2
3
4
public async Task<IEnumerable<TId>> GetAllAsync() => await Task.Run(() =>
{
    return context.Set<TId>().ToList().Select(b => b);
});
А если вот так, то в чем отличие?
C#
1
2
3
4
public async Task<IEnumerable<TId>> GetAllAsync() => await Task.Run(() =>
{
    return context.Set<TId>().ToList();
});
Добавлено через 13 минут
Все не дает покоя этот saferep. Взять за пример этот метод по добавлению. В целом в плане одноразового контекста все понятно, разве что только не понимаю зачем у одноразового контекста очищать отслеживание. Это как то что-то экономит или оптимизирует?

Но вот дальше вызывается событие. Пытался проследить логику его вызова. Но что-то никак. Объясните пожалуйста эту цепочку.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public async Task<TId> AddAsync(TId idDto)
{
    await Task.Run(() =>
    {
        using (DbContext context = contextCreator())
        {
            DbSet<TId> set = context.Set<TId>();
            set.Add(idDto);
            context.SaveChanges();
            context.ChangeTracker.Clear(); // Для чего такое действие?
            idDto = set.Find(idDto.Id) ?? throw new Exception("Чё-то не так.");
        }
    });
    RepChanged?.Invoke(this, RepChangedArgs<TId>.Add(idDto)); // Вот тут непонятно
    return idDto;
}
Добавлено через 12 минут
Элд Хасп, правильно ли я понял, что в методе Add сохранение в бд уже прошло до вызова события, а после у нас просто из-за этого события происходит добавление сущности в локальный кеш? Потому как в самом методе я не замечаю прежних действий по синхронизации коллекций из одноразового и постоянного контекстов.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
19.03.2025, 08:49
Цитата Сообщение от 2033 Посмотреть сообщение
А если вот так, то в чем отличие?
Это элементы безопасности. Делаю часто "на автомате".

Объяснение в чём безопасность.
Результат метода GetAllAsync - это ссылочный тип. Потребитель его получил и может делиться этим объектом с другими потребителями. Но так как это будет один и тот же объект, то любой из потребителей, если внесёт изменение в этот объект, то это изменение коснётся всех остальных потребителей тоже. Следовательно, возвращаемый объект либо должен уведомлять своих потребителей об собственном изменении, либо быть иммутабельным.

Результат .ToList().Select(b => b) является иммутабельным.
А результат (IEnumerable<TId>)....ToList() можно кастом привести к IList или к List<TId> и изменить. Встраивать в ответ метода объект, уведомляющий о собственных изменениях (например, ObservableCollection), на мой взгляд избыточно.

Цитата Сообщение от 2033 Посмотреть сообщение
В целом в плане одноразового контекста все понятно, разве что только не понимаю зачем у одноразового контекста очищать отслеживание. Это как то что-то экономит или оптимизирует?
В context была добавлена сущность idDto из параметров метода.
Мы её "скинули" в БД. Но в общем случае, в БД может быть своя логика, которая может несколько по другому записать значения idDto: что переформатировать , добавить/удалить и т.п. Например изменить регистр текста в каком-то поле или добавить актуальный штамп времени.
При этом нет гарантии, что изменения в БД будут и в сущности, которая в данный момент храниться в context. Поэтому мы очищаем context, заново читаем из БД сущность в него idDto = set.Find(idDto.Id) и дальше используем уже эту новую сущность гарантированно правильно отражающую запись БД.
Второй аспект - это обновление View (в общем случае любого потребителя репозитория).
Например сущность idDto предоставляется через свойство для привязки. У нас нет в требованиях, что сущность типа TId должна обязательно уведомлять о собственных изменениях. Следовательно изменение сущности не повлечёт уведомление привязкам о необходимости обновиться. Поэтому нам в свойстве надо заменить один экземпляр TId на другой. Вот этот другой, новый экземпляр метод и вернёт после после сброса контекста и нового чтения из БД.

Цитата Сообщение от 2033 Посмотреть сообщение
Но вот дальше вызывается событие. Пытался проследить логику его вызова. Но что-то никак. Объясните пожалуйста эту цепочку.
Не понял вопроса. Что собственно не понятно?
Подымается событие и в его параметре передаётся новый TId idDto.
Дальше потребитель репозитория, который прослушивает событие RepChanged может обновиться.

Почему не достаточно возврата return idDto;?
Потому что потребителей может быть несколько. Один из них вызвал метод AddAsync(TId idDto), получил его результат и может актуализировать своё состояние.
А другие потребители этого же экземпляра репозитория не узнают об этом и их состояние будет неактуальным.

Цитата Сообщение от 2033 Посмотреть сообщение
правильно ли я понял, что в методе Add сохранение в бд уже прошло до вызова события, а после у нас просто из-за этого события происходит добавление сущности в локальный кеш? Потому как в самом методе я не замечаю прежних действий по синхронизации коллекций из одноразового и постоянного контекстов.
В безопасном исполнении не используется же постоянный контекст.
В нём локальный кеш (если он нужен) создаётся уже на уровне потребителей репозитория.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
19.03.2025, 08:49
Цитата Сообщение от 2033 Посмотреть сообщение
А если вот так, то в чем отличие?
Это элементы безопасности. Делаю часто "на автомате".

Объяснение в чём безопасность.
Результат метода GetAllAsync - это ссылочный тип. Потребитель его получил и может делиться этим объектом с другими потребителями. Но так как это будет один и тот же объект, то любой из потребителей, если внесёт изменение в этот объект, то это изменение коснётся всех остальных потребителей тоже. Следовательно, возвращаемый объект либо должен уведомлять своих потребителей об собственном изменении, либо быть иммутабельным.

Результат .ToList().Select(b => b) является иммутабельным.
А результат (IEnumerable<TId>)....ToList() можно кастом привести к IList или к List<TId> и изменить. Встраивать в ответ метода объект, уведомляющий о собственных изменениях (например, ObservableCollection), на мой взгляд избыточно.

Цитата Сообщение от 2033 Посмотреть сообщение
В целом в плане одноразового контекста все понятно, разве что только не понимаю зачем у одноразового контекста очищать отслеживание. Это как то что-то экономит или оптимизирует?
В context была добавлена сущность idDto из параметров метода.
Мы её "скинули" в БД. Но в общем случае, в БД может быть своя логика, которая может несколько по другому записать значения idDto: что переформатировать , добавить/удалить и т.п. Например, задать актуальный Id, изменить регистр текста в каком-то поле или добавить актуальный штамп времени.
При этом нет гарантии, что изменения в БД будут и в сущности, которая в данный момент храниться в context. Поэтому мы очищаем context, заново читаем из БД сущность в него idDto = set.Find(idDto.Id) и дальше используем уже эту новую сущность гарантированно правильно отражающую запись БД.
Второй аспект - это обновление View (в общем случае любого потребителя репозитория).
Например сущность idDto предоставляется через свойство для привязки. У нас нет в требованиях, что сущность типа TId должна обязательно уведомлять о собственных изменениях. Следовательно изменение сущности не повлечёт уведомление привязкам о необходимости обновиться. Поэтому нам в свойстве надо заменить один экземпляр TId на другой. Вот этот другой, новый экземпляр метод и вернёт после после сброса контекста и нового чтения из БД.

Цитата Сообщение от 2033 Посмотреть сообщение
Но вот дальше вызывается событие. Пытался проследить логику его вызова. Но что-то никак. Объясните пожалуйста эту цепочку.
Не понял вопроса. Что собственно не понятно?
Подымается событие и в его параметре передаётся новый TId idDto.
Дальше потребитель репозитория, который прослушивает событие RepChanged может обновиться.

Почему не достаточно возврата return idDto;?
Потому что потребителей может быть несколько. Один из них вызвал метод AddAsync(TId idDto), получил его результат и может актуализировать своё состояние.
А другие потребители этого же экземпляра репозитория не узнают об этом и их состояние будет неактуальным.

Цитата Сообщение от 2033 Посмотреть сообщение
правильно ли я понял, что в методе Add сохранение в бд уже прошло до вызова события, а после у нас просто из-за этого события происходит добавление сущности в локальный кеш? Потому как в самом методе я не замечаю прежних действий по синхронизации коллекций из одноразового и постоянного контекстов.
В безопасном исполнении не используется же постоянный контекст.
В нём локальный кеш (если он нужен) создаётся уже на уровне потребителей репозитория.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.03.2025, 08:49

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
240
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
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