Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.53/15: Рейтинг темы: голосов - 15, средняя оценка - 4.53
0 / 0 / 0
Регистрация: 30.08.2019
Сообщений: 58

RelayCommand как передать переменную

09.10.2019, 16:13. Показов 3585. Ответов 5

Студворк — интернет-сервис помощи студентам
Всем привет, пишу MVVM приложение
По умолчанию во всех туториалах и так на форумах читал, что
комманды делаются через класс RelayCommand, который наследуется от ICommand.
Сначала создается метод со входными object parameter, например так:
C#
1
void DeleteEntity(object parameter)
а потом пишут что-то вроде такого
C#
1
2
public RelayCommand DeleteCommand { get; set; }
DeleteCommand = new RelayCommand(DeleteEntity);
Так делал и я. Проблем не было Но сейчас захотел немного оптимизировать код
Заметил что огромные куски кода копируются в каждую вью-модель с незначительными изменениями.
Поэтому пришла мысль создать базовый класс ViewModelBase, куда запихнуть всё -
а все остальные вью-модели унаследовать от него, чтобы каждый раз не копировать огромные куски...

Но здесь возникли проблемы...

Вот например
C#
1
2
3
4
5
6
7
8
9
10
11
void DeleteEntity(object parameter, PassportRawConeBusinessObject passportrawconeBO)
        {
            var _passportrawcone = SelectedPassRawCone as PassRawConeUniversal;
            if (SelectedIndex != -1)
            {
                passportrawconeBO.DeletePassportRawCone(_passportrawcone);
                RaisePropertyChanged("PassRawConeOC"); // Update the list from the data source
            }
            else
                SelectedPassRawCone = null; // Simply discard the new object
        }
Как видно по коду, в метод на удаление передается переменная passportrawconeBO из другого класса.
Всё остальное в методе не меняется, и это как и два других метода, постоянно копируются в каждую вью-модель.
Т. е. я модернизировал входные параметры метода и написал так
(object parameter, PassportRawConeBusinessObject passportrawconeBO)
с надеждой запихнуть это в класс ViewModelBase и остальные вью-модели унаследовать от него..

Но теперь возникли проблемы с RelayCommand -
компилятор ругается на
C#
1
DeleteCommand = new RelayCommand(DeleteEntity);
и предлагает создать конструктор двумя способами
так
C#
1
2
3
public RelayCommand(Action<object, PassportRawConeBusinessObject> deleteEntity)
        {
        }
или вот так
C#
1
2
3
4
public RelayCommand(Action<object, PassportRawConeBusinessObject> deleteEntity)
        {
            this.deleteEntity = deleteEntity;
        }
Пробовал указанными способами, программа компилируется запускается,
но в итоге нужный функционал не работает Колупался весь день сегодня но не смог ничего сделать...

Если кто из ПРО сможет помочь - отпишитесь, как будет время...
да...Много написано...но может мало что понятно...
поэтому окончательно ещё раз сформулирую свой вопрос

Как в RelayCommand унаследованный от ICommand передать переменную...в конструктор или ещё как-то...
т.е. чтобы было не так
C#
1
(object parameter)
а вот так
C#
1
(object parameter, PassportRawConeBusinessObject passportrawconeBO)
Заранее огромное спасибо!
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
09.10.2019, 16:13
Ответы с готовыми решениями:

RelayCommand
Здравствуйте. У меня стоит задача сделать так, чтобы после нажатия кнопки менялось свойство Visability у нескольких сеток Grid. Так как в...

RelayCommand
Добрый день, покажите пожалуйста пример relaycommand на примере моего приложения. &lt;Window x:Class=&quot;View.MainWindow&quot; ...

RelayCommand.cs не найден
Пишу на wpf приложение, установил MVVM lights. В using указаны: using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; ...

5
17 / 14 / 7
Регистрация: 04.02.2017
Сообщений: 486
09.10.2019, 20:44
trimagick77, Если я правильно понимаю вам надо чтоб команда срабатывалась при определённом условии?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16130 / 11254 / 2888
Регистрация: 21.04.2018
Сообщений: 33,086
Записей в блоге: 2
10.10.2019, 07:28
Лучший ответ Сообщение было отмечено trimagick77 как решение

Решение

trimagick77, из ваших объяснений не понятно откуда надо брать второй параметр.
Допустим, если метод DeleteEntity принадлежит базовому классу и должен входным параметром принимать разные значения в зависимости от производного класса, то в производном можно объявить команду так:
C#
1
2
3
4
private RelayCommand _deleteCommand;
public RelayCommand DeleteCommand
      => _deleteCommand
            ?? ( _deleteCommand= new RelayCommand(param => DeleteEntity(param, Свойство));
Или так
C#
1
2
3
4
5
private RelayCommand _deleteCommand;
public RelayCommand DeleteCommand
      => _deleteCommand
            ?? ( _deleteCommand= new RelayCommand(DeleteEntit);
private void DeleteEntity(object param) => DeleteEntity(param, Свойство);
Способы похожие, но работать могут чуть по разному.
2
0 / 0 / 0
Регистрация: 30.08.2019
Сообщений: 58
10.10.2019, 09:57  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
ваших объяснений не понятно откуда надо брать второй параметр
Спасибо за очередно ответ. ОК.
Поробую объяснить по-другому.
В данный момент исходный код ViewModelBase выглядит так
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
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;
 
namespace Semenovodstvo.ViewModel
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        //basic ViewModelBase
        internal void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
        }
        public event PropertyChangedEventHandler PropertyChanged;
 
        //Extra Stuff, shows why a base ViewModel is useful
        bool? _CloseWindowFlag;
        public bool? CloseWindowFlag
        {
            get { return _CloseWindowFlag; }
            set
            {
                _CloseWindowFlag = value;
                RaisePropertyChanged("CloseWindowFlag");
            }
        }
        public virtual void CloseWindow(bool? result = true)
        {
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
            {
                CloseWindowFlag = CloseWindowFlag == null
                    ? true
                    : !CloseWindowFlag;
            }));
        }
        object _selectedpassrawcone;
        /// <summary>Объект из выбранного экземпляра, реализирующий OnPC </summary>
        public object SelectedPassRawCone
        {
            get
            {
                return _selectedpassrawcone;
            }
            set
            {
                if (_selectedpassrawcone != value)
                {
                    _selectedpassrawcone = value;
                    RaisePropertyChanged("SelectedPassRawCone");
                }
            }
        }
        /// <summary>Выбранный индекс объекта для операций добавления/удаления</summary>
        public int SelectedIndex { get; set; } = -666;  //Задаем недостижимое значение по умолчанию на случай добавления первой записи если таблица пуста
 
        BindingGroup _UpdateBindingGroup;
        /// <summary>BindingGroup, реализир. OnPC </summary>
        public BindingGroup UpdateBindingGroup
        {
            get
            {
                return _UpdateBindingGroup;
            }
            set
            {
                if (_UpdateBindingGroup != value)
                {
                    _UpdateBindingGroup = value;
                    RaisePropertyChanged("UpdateBindingGroup");
                }
            }
        }
        /// <summary>Метод отмены для RelayCommand</summary>
        public void DoCancel(object param)
        {
            UpdateBindingGroup.CancelEdit();
            if (SelectedIndex == -1)    //This only closes if new - just to show you how CancelEdit returns old values to bindings
                SelectedPassRawCone = null;
        }
        /// <summary>Метод добавления для RelayCommand</summary>
        public void AddEntity<T>(object parameter) where T : new()
        {
            SelectedPassRawCone = null; // Unselects last selection. Essential, as assignment below won't clear other control's SelectedItems
            var _passportrawcone = new T();
            SelectedPassRawCone = _passportrawcone;
        }
    }
}
А код одной из вью-модели, которая наследуются от неё выглядит так
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
using Semenovodstvo.Model;
using Semenovodstvo.Model.Entities;
using Semenovodstvo.Model.Entities.Passports;
using Semenovodstvo.Model.Entities.Seed;
using Semenovodstvo.ViewModel.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;
 
namespace Semenovodstvo.ViewModel
{
    /// <summary>Формируем новый класс с полями, необходимыми для отображения во View</summary>
    public class PassRawConeUniversal
    {
        /// <summary>ИД паспорта</summary>
        public int IdPR { get; set; }
        public string Specless { get; set; }
        /// <summary>Биологический вид растения (латинское название)</summary>
        public string SpeclessLatin { get; set; }
        /// <summary>Масса паспорта</summary>
        public int Mass { get; set; }
        /// <summary>Квартал</summary>
        public string Kv { get; set; }
        /// <summary>Выдел</summary>
        public string Vd { get; set; }
    }
    /// <summary>Класс реализирующий методы заполнения,
    /// добавления, удаления, обновления из Модели, выше созданного класса
    /// а также событие на изменение</summary>
    public class PassportRawConeBusinessObject
    {
        /// <summary>Определяем событие на изменение</summary>
        public event EventHandler PassRawConesChanged;
        /// <summary>Определяем новый лист из объектов созданного класса</summary>
        List<PassRawConeUniversal> PassRawCones { get; set; }
        /// <summary>Метод заполнения/преобразования данных из Модели в универсальный List</summary>
        public List<PassRawConeUniversal> GetPassRawCones()
        {
            using (var context = new SeedContext())  //подключаемся к контексту БД
            {
                var q =
                    from PR in context.Passports
                   from ForSite in context.ForestSities
                    where
               ForSite.Id == PR.SeedCollection.ForestSite.Id
                    select new PassRawConeUniversal    //явно преобразовавыем выбранные данные из БД к нужному типу
                    {
                        IdPR = PR.Id,
                        Mass = PR.Mass,
                        Kv = ForSite.Kv,
                        Vd = ForSite.Vd,
                    };
 
                PassRawCones = q.ToList();
            }
            return PassRawCones;
        }
        /// <summary>Метод добавления нового объекта в созданный выше список List,
        /// а также в Модель</summary>
        public void AddPassportRawCone(PassRawConeUniversal _passportraw)
        {          
            PassRawCones.Add(_passportraw); //Добавляем новый объект в список
 
            using (var context = new SeedContext()) //подключаемся к контексту БД
            {
                ForestSite query1 = //Выбираем первый объект из таблицы соотв. критерию
                    context.ForestSities.FirstOrDefault(item => (item.Kv == _passportraw.Kv && item.Vd == _passportraw.Vd));
                if (query1 == null) //если объект в таблице отсутсвует, создаем новый
                {
                    context.ForestSities.Add(new ForestSite { Kv = _passportraw.Kv, Vd = _passportraw.Vd });
                    context.SaveChanges();
                };
                query1 = //Заново выбираем (теперь на 100% существующий) первый объект из таблицы соотв. критерию
                    context.ForestSities.FirstOrDefault(item => (item.Kv == _passportraw.Kv && item.Vd == _passportraw.Vd));
                               
                Passport _passrow = new Passport();  
                _passrow.Mass = _passportraw.Mass;
 
                if (context.SeedCollection.FirstOrDefault(item => item.ForestSite.Id == query1.Id) == null)
                {    //если объект в таблице отсутсвует, создаем новый
                    _passrow.SeedCollection = new SeedCollection();
                    _passrow.SeedCollection.ForestSite = query1;
                }
                else
                {    //если же объект существует, то присваиваем ему значение согласно ИДшнику
                    _passrow.SeedCollection = context.SeedCollection.FirstOrDefault(item => item.ForestSite.Id == query1.Id);
                }
 
                context.Passports.Add(_passrow); 
                context.SaveChanges(); 
            }
 
            OnPassRawConesChanged();
        }
        /// <summary>Метод удаления объекта из списка List, а также из Модели</summary>
        public void DeletePassportRawCone(PassRawConeUniversal _passportraw)
        {
            PassRawCones.Remove(_passportraw); //Удаляем объект из списка
 
            using (var context = new SeedContext())  //подключаемся к контексту БД
            {
                // Execute the query, and make changes you wanted
                context.Passports.Remove(context.Passports.FirstOrDefault(item => item.Id == _passportraw.IdPR));
                context.SaveChanges();
            }
 
            OnPassRawConesChanged();
        }
        /// <summary>Метод обновления полей объекта в Модели</summary>
        public void UpdatePassportRawCone(PassRawConeUniversal _passportraw)
        {
            using (var context = new SeedContext())   //подключаемся к контексту БД
            {
                // Query the database for the rows to be updated.
                Passport query1 =  //Выбираем первый объект из таблицы соотв. критерию
                    context.Passports.FirstOrDefault(item => item.Id == _passportraw.IdPR);
 
                ForestSite query2 =   //Выбираем первый объект из таблицы соотв. критерию
                    context.ForestSities.FirstOrDefault(item => (item.Kv == _passportraw.Kv && item.Vd == _passportraw.Vd));
                if (query2 == null) //если объект в таблице отсутсвует, создаем новый
                {
                    context.ForestSities.Add(new ForestSite { Kv = _passportraw.Kv, Vd = _passportraw.Vd });
                    context.SaveChanges();
                };
                query2 =     //Заново выбираем (теперь на 100% существующий) первый объект из таблицы соотв. критерию
                    context.ForestSities.FirstOrDefault(item => (item.Kv == _passportraw.Kv && item.Vd == _passportraw.Vd));
 
                // Execute the query, and change the column values
                // you want to change.
 
                if (context.SeedCollection.FirstOrDefault(item => item.ForestSite.Id == query2.Id) == null)
                {   //если объект в таблице отсутсвует, создаем новый
                    query1.SeedCollection = new SeedCollection();
                    query1.SeedCollection.ForestSite = query2;
                }
                else
                {   //если же объект существует, то присваиваем ему значение согласно ИДшнику
                    query1.SeedCollection = context.SeedCollection.FirstOrDefault(item => item.ForestSite.Id == query2.Id);
                }
 
                query1.Mass = _passportraw.Mass;                
                context.SaveChanges();
            }
        }
        /// <summary>Изменился ли объект?</summary>
        void OnPassRawConesChanged()
        {
            if (PassRawConesChanged != null)
                PassRawConesChanged(this, null);
        }
    }
    /// <summary>Основной класс Вью-Модели</summary>
    public class VMPassportRawCone : ViewModelBase
    {
        /// <summary>Создаем экземпляр созданного выше бизнес-класса</summary>
        PassportRawConeBusinessObject passportrawconeBO; // The sealed business object (database layer, web service, etc)
 
        ObservableCollection<PassRawConeUniversal> _passrawconeOC;
        /// <summary>Создаем ObservableCollection из List используя метод заполнения</summary>
        public ObservableCollection<PassRawConeUniversal> PassRawConeOC
        {
            get
            {
                _passrawconeOC = new ObservableCollection<PassRawConeUniversal>(passportrawconeBO.GetPassRawCones());
                return _passrawconeOC;
            }
        }
        /// <summary>Команда на отмену</summary>
        public RelayCommand CancelCommand { get; set; }
        /// <summary>Команда на сохранения изменений</summary>
        public RelayCommand SaveCommand { get; set; }
        /// <summary>Команда на добавление экземпляра</summary>
        public RelayCommand AddPassRawConeCommand { get; set; }
        /// <summary>Команда на удаление экземпляра</summary>
        public RelayCommand DeletePassRawConeCommand { get; set; }
        /// <summary>Конструктор по умолчанию для Вью-Модели</summary>
        public VMPassportRawCone()
        {
            passportrawconeBO = new PassportRawConeBusinessObject();
            passportrawconeBO.PassRawConesChanged += new EventHandler(passportrawconeBO_PassRawConeOCChanged);
 
            CancelCommand = new RelayCommand(DoCancel);
            SaveCommand = new RelayCommand(DoSave);
            AddPassRawConeCommand = new RelayCommand(AddEntity<PassRawConeUniversal>);
            DeletePassRawConeCommand = new RelayCommand(DeleteEntity);
 
            UpdateBindingGroup = new BindingGroup { Name = "Group1" };
        }
        /// <summary>Запускаем событие на изменение</summary>
        void passportrawconeBO_PassRawConeOCChanged(object sender, EventArgs e)
        {
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
            {
                RaisePropertyChanged("PassRawConeOC");
            }));
        }
        /// <summary>Метод сохранения для RelayCommand</summary>
        void DoSave(object param)
        {
            UpdateBindingGroup.CommitEdit();
            var _passportrawcone = SelectedPassRawCone as PassRawConeUniversal;
            if ((SelectedIndex == -1) || (SelectedIndex == -666))  //проверяем не выбран ли существующий объект или же datagrid пуст
            {
                passportrawconeBO.AddPassportRawCone(_passportrawcone);
                RaisePropertyChanged("PassRawConeOC"); // Update the list from the data source
            }
            else
                passportrawconeBO.UpdatePassportRawCone(_passportrawcone);
 
            SelectedPassRawCone = null;
        }
        /// <summary>Метод удаления для RelayCommand</summary>
        void DeleteEntity(object parameter)
        {
            var _passportrawcone = SelectedPassRawCone as PassRawConeUniversal;
            if (SelectedIndex != -1)
            {
                passportrawconeBO.DeletePassportRawCone(_passportrawcone);
                RaisePropertyChanged("PassRawConeOC"); // Update the list from the data source
            }
            else
                SelectedPassRawCone = null; // Simply discard the new object
        }
 
    }
}
Изначально методы
C#
1
public void DoCancel(object param)
и
C#
1
public void AddEntity<T>(object parameter) where T : new()
были в наследуемой вью-модели, а не в базовой.
Т.е. мне удалось уже модернизировать эту часть и запихнуть их в базовую вью-модель,
чтобы не копировать их каждый раз потом в каждой вью-модели.
Отлично.
Но теперь тоже самое нужно сделать с методами
C#
1
void DoSave(object param)
и
C#
1
void DeleteEntity(object parameter)
Как их запихнуть в базовую вью-модель ViewModelBase???
Отличие этих методов в том, что здесь как-то нужно передавать переменную passportrawconeBO
Я пробовал это сделать так
C#
1
void DeleteEntity(object parameter, PassportRawConeBusinessObject passportrawconeBO)
как писал в первом сообщении темы.
Но тогда компилятор стал ругаться на RelayCommand - как я и написал выше.

Надеюсь теперь вы меня поняли.

Еще раз спасибо за ответ.
Попробую переделать по Вашему способу.

Добавлено через 30 минут
ВСЁ ПЕРЕДЕЛАЛ.
ПРО ВАШЕМУ СПОСОБУ ВСЁ РАБОТАЕТ.
Элд Хасп - ВЫ ГЕНИЙ!!!!
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16130 / 11254 / 2888
Регистрация: 21.04.2018
Сообщений: 33,086
Записей в блоге: 2
10.10.2019, 11:18
trimagick77, ну и слава Богу!
А то я посмотрел на ваш код....
И думаю как же со смарта его разбирать...
0
0 / 0 / 0
Регистрация: 30.08.2019
Сообщений: 58
10.10.2019, 11:25  [ТС]
Элд Хасп, может знаете, как это переделать?
https://www.cyberforum.ru/csha... 09932.html
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.10.2019, 11:25
Помогаю со студенческими работами здесь

ViewModel: RelayCommand и метод
Привет всем, Элд Хасп, Я закрывал окно в Сode Behind таким образом. Теперь использую ViewModel. private void...

Спам CanExecute в RelayCommand
Добрый день, я думал что CanExecute выполняется по клику или еще какому-то действую над объектом, оказывается они спамом n мс выполняются....

RelayCommand и асинхронный код
Здравствуйте. Есть некая кнопка, к которой привязана команда &lt;Button x:Name=&quot;SendMessageButton&quot; Command=&quot;{Binding...

Как передать ссылку на переменную?
При создании объекта класса, в него передается переменная int, значение которого присваивается переменной i класса A. Как присвоить не...

Как заголовок формы передать в переменную?
как заголовок формы передать в переменную на C# Добавлено через 45 секунд К примеру я зашел в таблицу ответственные лица и место...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru