Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.50/4: Рейтинг темы: голосов - 4, средняя оценка - 4.50
198 / 93 / 43
Регистрация: 09.11.2019
Сообщений: 414

Архитектура оконного приложения

27.09.2021, 20:06. Показов 928. Ответов 2

Студворк — интернет-сервис помощи студентам
Всем привет.

Опишу проблему целиком, думаю, её суть станет понятна по ходу.

Итак, имеется некая предметная область.
Пусть это будет, например, движение машинок по трассе. Трасса может быть представлена как обычная дорога, как шоссе, как тоннель. Тоннель характерен тем, что там используется однополосное и одностороннее движение по светофору. Два других типа дороги конфигурируются по кол-ву полос, по направлению движения. Скорость машинок задаётся по какому-нибудь случайному закону распределения. Подобным же образом задаётся интервал между появлениями новых машинок на трассе - интенсивность движения.

Всё это отрисовывается в GUI. Все настройки задаются так же через GUI.
Для каждой настройки я создаю новое окошко, а предыдущее скрываю через Hide(), чтоб была возможность вызвать это окошко через кнопку Назад на основной форме.
Соответственно, получается несколько окошек настроек:

Тип трассы -> Дорога/шоссе -> настройки выбранного типа дороги -> распределение потока движения -> распределение скорости транспорта -> основная форма для отрисовки
// для распределения используется одно и то же окошко, но это два разных объекта
Либо
Тип трассы -> Тоннель -> распределение потока движения -> распределение скорости транспорта -> задание настроек светофора -> основная форма для отрисовки.

И вот уже вот тут видна суть проблемы - приходится открывать разные окошки для разных типов дорог, какими-то if'ами отслеживать, а какая форма была открыта до этого/какой тип имеет трасса, чтоб обеспечить дальнейшее корректное функционирование.

Конфигурация всей системы описывается следующим образом:
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
 public class SystemConfiguration
{
        public RoadConfiguration RoadConfig { get; set; }
        public CarConfiguration CarConfig { get; set; }
       // конструкторы всякие, проверки
}
 
 
public class RoadConfiguration
    {
        public IRoadSettings Road { get; set; }
 
        public IIntensity Intensity { get; set; }
       // конструкторы всякие, проверки
}
 
 public class CarConfiguration
    {
        public IIntensity Speed { get; set; }
 
        // конструкторы всякие, проверки
}
// этот интерфейс реализует n-ое количество распределений
 public interface IIntensity : IValidatableObject
    {
        string FirstDescription { get; set; }
        string SecondDescription { get; set; }
        double FirstParam { get; set; }
        double SecondParam { get; set; }
 
        IEnumerable<double> NextSample();
 
        bool CheckParam(double param);
    }
 
public interface IRoadSettings
    {
        ITraffic Traffic { get; set; } //настройки движения - куда и сколько полос
 
        string PathToImgSign { get; set; }
    }
 
 public interface ITraffic : IValidatableObject
    {
        DirectionEnum Direction { get; }
 
        IDictionary<DirectionEnum, int> Lines { get; set; }
    }
 
// здесь всё ок, обычная реализация
 public class HighwaySettings : IRoadSettings  
    {
        public ITraffic Traffic { get; set; }
        public string PathToImgSign { get; set; }
}
 
// здесь добавляется новое свойство. Чтоб до этого свойства добраться нужно, во-первых, пройтись по веренице свойств, а затем ещё скастить к TunnelSettings 
 public class TunnelSettings : IRoadSettings
    {
        public ITraffic Traffic { get; set; }
        public string PathToImgSign { get; set; }
        public SemaphoreConfiguration SemaphoreConfiguration { get; set; }
}
Итак, что меня конкретно не устраивает:
1. В основной форме я обращаюсь к объектам примерно так:
C#
1
2
3
4
5
6
7
8
countPassingRoads = _systemConfig.RoadConfig.Road.Traffic.Lines[DirectionEnum.One];
 
            if(_systemConfig.RoadConfig.Road.Traffic is DirectionTwo)
            {
                countOppositeRoads = _systemConfig.RoadConfig.Road.Traffic.Lines[DirectionEnum.Two];
            }
//или так 
var speed = _systemConfig.CarConfig.Speed.NextSample().First();
2. Из-за того, что тоннель не имеет окошка для настройки полос и направления движения, но имеет окошко для настройки светофора(по сути дополнительное свойство), мне приходится обкладываться следующими костылями:
C#
1
2
3
4
5
6
7
8
9
10
11
12
 if (_prevForm is MainWindow)
                {
                    var tunnelSettings = ((TunnelSettings)_systemConfiguration.RoadConfig.Road);
                    tunnelSettings.SemaphoreConfiguration.TimeMilliseconds = _semaphoreConfigurationToChange.TimeMilliseconds;
                    Close();
                }
                else
                {
                    var form = new MainWindow(this, _systemConfiguration);
                    form.Show();
                    this.Hide();
                }
3. Мне приходится протаскивать через конструкторы форм(а их штуки 4-5) весь объект или части объекта SystemConfiguration, и на ходу его "долеплять" до полноценного состояния - когда заданы все свойства и все настройки.
4. Через эти же конструкторы форм мне приходится тянуть ссылку на предыдущую форму. Причем используя метод Hide, я не закрываю предыдущую форму, а просто скрываю. Поэтому при закрытии основной формы у меня где-то там висит скрытое окошко. Я пока это не лечил, но подозреваю, что придётся вдобавок через все формы тащить список ссылок на уже отработавшие формы, чтоб в основной форме их все разом закрыть.


Что из этого можно вылечить и как это сделать?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
27.09.2021, 20:06
Ответы с готовыми решениями:

Зависание оконного приложения при прослушке порта
private void button1_Click(object sender, EventArgs e) { TcpListener listner = new TcpListener(new...

Архитектура многопоточного приложения
Всем доброго времени суток. На даннй момент есть следующая задача: реализовать winForm приложение на основе потоков: в первом потоке...

Универсальная хост-плагинная архитектура приложения
Доброго времени суток, уважаемые форумчане. Обращаюсь к вас за советами-ответами :) По мере создания новых приложений для одной...

2
148 / 92 / 56
Регистрация: 03.02.2021
Сообщений: 284
29.09.2021, 12:21
Может это повредит инкапсуляции (но не думаю), но я бы реализовал это примерно так:
1) Видоизменил бы публичный класс SystemConfiguration, в котором перечислил бы все настройки, которые изменяются во всей этой цепочке окон (тип трассы, настройки светофора, скорость транспорта и т.д.), а сами ссылки на окна убрал.
2) При нажатии кнопки "Опции" создается форма, скажем, fOpt1 в качестве входного параметра конструктора передается объект класса SystemConfiguration.
3) Пользователь выбирает тип трассы и нажимает "Далее". В параметр TraceType заносится тип трассы и в зависимости от выбранного типа создается та или иная форма и ей в конструктор передается все тот же SystemConfiguration.
4) После этого форму fOpt1 можно с чистой совестью удалять, поскольку если пользователь нажмет "Назад" по данным из SystemConfiguration, можно сразу понять какая форма нужна, создать ее, передать на вход все тот же конфиг и из этого конфига заполнить все поля теми данными, которые пользователь ввел ранее.
0
198 / 93 / 43
Регистрация: 09.11.2019
Сообщений: 414
29.09.2021, 12:31  [ТС]
Цитата Сообщение от sfumatori Посмотреть сообщение
1) Видоизменил бы публичный класс SystemConfiguration, в котором перечислил бы все настройки, которые изменяются во всей этой цепочке окон (тип трассы, настройки светофора, скорость транспорта и т.д.), а сами ссылки на окна убрал.
Да, к этому я уже пришёл и сделал.

Цитата Сообщение от sfumatori Посмотреть сообщение
2) При нажатии кнопки "Опции" создается форма, скажем, fOpt1 в качестве входного параметра конструктора передается объект класса SystemConfiguration.
3) Пользователь выбирает тип трассы и нажимает "Далее". В параметр TraceType заносится тип трассы и в зависимости от выбранного типа создается та или иная форма и ей в конструктор передается все тот же SystemConfiguration.
Так тоже сделал уже.

Цитата Сообщение от sfumatori Посмотреть сообщение
4) После этого форму fOpt1 можно с чистой совестью удалять, поскольку если пользователь нажмет "Назад" по данным из SystemConfiguration, можно сразу понять какая форма нужна, создать ее, передать на вход все тот же конфиг и из этого конфига заполнить все поля теми данными, которые пользователь ввел ранее.
А вот с этим вынужден не согласиться - легче держать ссылку на открытую, но скрытую форму. Ну а текущая форма удаляется, да, она не нужна уже.
Проблему закрытия форм решил через контейнер-синглтон и метод-расширение для Form.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
29.09.2021, 12:31
Помогаю со студенческими работами здесь

Превью оконного приложения
Добрых времени суток. Интересует собственно вот что, можно ли в обычный вин форм вывысти все, что происходит в другом свернутом приложении,...

Проектирование оконного приложения
Здравствуйте уважаемые форумчане. Возникла задача создать приложение для работы с БД через оконный интерфейс. Решил в этом деле...

Запуск оконного приложения в терминальном сеансе определённого пользователя
Доброго времени суток. Нужно реализовать следующее: На терминальном сервере есть служба которая должна по запросу запускать оконное...

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

Архитектура приложения
Существует литература по построению архитектуры приложений?


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

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а привычная функция main(). . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь(не выше 3-го порядка) постоянного тока с элементами R, L, C, k(ключ), U, E, J. Программа находит переходные токи и напряжения на элементах схемы классическим методом(1 и 2 з-ны. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru