Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34

Создание программы - ООП модель, MVP

30.10.2018, 11:10. Показов 70111. Ответов 99

Студворк — интернет-сервис помощи студентам
Пример разработки приложения с нуля под WinForms

Рассматриваются такие аспекты разработки как:
  • Создание ООП модели предметной области.
  • Разработка Unit-тестов.
  • Архитектура приложения под WinForms.
  • Разработка пользовательского интерфейса с разделением модели и представления (MVP).
  • Разработка UserControl для построения пользовательского интерфейса.
  • Рефакторинг, непрерывная интеграция.
  • Организация проекта в VisualStudio.

В этом примере НЕ рассматриваются шаблоны типа фабрик, не рассматривается внедрение зависимостей (DI).
Используется простой вариант шаблона Model-View-Presenter, адаптированный под специфику WinForms.

Этот топик перекликается с этим FAQ, и является практическим примером к нему.
Комментарии и вопросы - приветствуются.

Постановка задачи

Требуется создать приложение - опросник.

Опросник будет состоять из нескольких вопросов с различными вариантами ответов.
Вопросы могут быть двух видов - с выбором одного ответа из набора возможных, и открытые вопросы, в которых респондент может указать произвольный ответ в виде текста.
В опроснике нужно предусмотреть возможность задавать некоторые вопросы и альтернативы только при выполнении некоторых условий, например если в предыдущем вопросе респондент выбрал определенный ответ.

Приложение должно состоять из двух частей - конструктора опросника и приложения в котором респондент может ответить на вопросы готового опросника.

Результаты опроса должны выгружаться в виде, пригодном для дальнейшей обработки.
18
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.10.2018, 11:10
Ответы с готовыми решениями:

Встраивание Google RESTful pattern A в модель MVP
Доброго дня. Всем известна модель MVC и её разновидность MVP, достаточно подробную статью по реализации MVP можно посмотреть здесь А...

Создание дочернего окна в MVP
Продолжаю разбираться с MVP. Не знаю, как правильно в данном шаблоне сделать работу с дочерним окном. Есть главное окно MainForm,...

ООП. Переделать фрагмент программы под ООП
Есть небольшой фрагмент из программы, который необходимо перестроить под ООП(создать класс), для удобного испольщования. Можно ли изменить...

99
#MRoose
 Аватар для MIRAMIX
8 / 9 / 3
Регистрация: 22.02.2013
Сообщений: 416
11.11.2018, 23:19
Студворк — интернет-сервис помощи студентам
Storm23, спасибо, получилось, хотя не понял, какое отношение эта строчка имеет к остальному коду...

Хоть что-то сам теперь попробую - вывести в лейблы заполненные ответы и вопросы к ним
0
#MRoose
 Аватар для MIRAMIX
8 / 9 / 3
Регистрация: 22.02.2013
Сообщений: 416
16.11.2018, 18:30
Storm23, еще не подскажите по вот этой части :
Кликните здесь для просмотра всего текста
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
using System.Data.OleDb;
using System.Linq;
 
namespace QuestCoreNS
{
    /// <summary>
    /// Экспорт в базу данных
    /// </summary>
    public class ExportToDB
    {
        public string ConnectionString { get; set; } = @"Provider=Microsoft.ACE.OleDb.12.0; data source=F:\export.xlsx;Extended Properties=Excel 12.0";
        public string TableName { get; set; } = "Лист1$";
        public bool ExportAltTextInsteadOfCode { get; set; } = false;
 
        public void Export(Questionnaire questionnaire, Anketa anketa)
        {
            using (var conn = new OleDbConnection(ConnectionString))
            {
                //формируем список колонок
                var columnsList = string.Join(", ", questionnaire.Select(q => q.Id));
 
                //формируем список параметров
                var paramsList = string.Join(", ", questionnaire.Select(q => "@" + q.Id));
                var sql = string.Format("INSERT INTO [{2}]({0}) VALUES({1});", columnsList, paramsList, TableName);
 
                //создаем команду
                using (var command = new OleDbCommand(sql, conn))
                {
                    //инициализируем параметры значениями
                    foreach (var q in questionnaire)
                    {
                        var answer = anketa.FirstOrDefault(a => a.QuestId == q.Id);
                        var val = GetExportedAlternativeValue(q, answer);
                        command.Parameters.AddWithValue("@" + q.Id, val);
                    }
 
                    //исполняем SQL запрос
                    conn.Open();
                    command.ExecuteNonQuery();
                }
 
                conn.Close();
            }
        }
 
        private object GetExportedAlternativeValue(Quest quest, Answer answer)
        {
            if (answer == null) return null;
 
            if (ExportAltTextInsteadOfCode)
            {
                if (answer.Text != null)
                    return answer.Text;
                var alt = quest.FirstOrDefault(a => a.Code == answer.AlternativeCode);
                return alt?.Title;
            }
            else
            {
                return answer.ToString();
            }
        }
    }
}


она записывает в нужные ячейки, но в новую строку. Нужно записать в строку, где первые столбцы (id, ФИО1, логин1, логин2, логин3) уже заполнены.
А заполняются они вместе с нажатием Завершить у формы QuestInterview.
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
16.11.2018, 18:35  [ТС]
Цитата Сообщение от MIRAMIX Посмотреть сообщение
она записывает в нужные ячейки, но в новую строку. Нужно записать в строку, где первые столбцы (id, ФИО1, логин1, логин2, логин3) уже заполнены.
А заполняются они вместе с нажатием Завершить у формы QuestInterview.
Думаю, тогда нужно использовать не INSERT а UPDATE с условием (типа UPDATE ... WHERE Id = ....).
Хотя я не уверен, что это будет работать в Экселе.
1
#MRoose
 Аватар для MIRAMIX
8 / 9 / 3
Регистрация: 22.02.2013
Сообщений: 416
16.11.2018, 19:14
Storm23, у меня сложность (пока) с пониманием модели опросника.
я модифицировал конструктор формы QuestInterview так :
Кликните здесь для просмотра всего текста
C#
1
public test_opr(Questionnaire questionnaire, string load_path, string save_path, int num) : this()


load_path - другая форма передает сразу нужный путь (так как их много, определяются в другой форме)
save_path - аналогично
num - 0 или 1, 1 для теста из конструктора (сразу закроет форму) и 0 для внесения данных.

вызов метода экспорта в эксель тоже изменил
Кликните здесь для просмотра всего текста
C#
1
new ExportToDB().Export(questionnaire, anketa, path2);


Все хорошо, можно спокойно передать готовые string, но вот не пойму как встроить мои данные в этот участок :
Кликните здесь для просмотра всего текста
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
public void Export(Questionnaire questionnaire, Anketa anketa, string save_path)
        {
            path=save_path;
            using (var conn = new OleDbConnection(ConnectionString))
            {
                //формируем список колонок
                var columnsList = string.Join(", ", questionnaire.Select(q => q.Id));
 
                //формируем список параметров
                var paramsList = string.Join(", ", questionnaire.Select(q => "@" + q.Id));
                var sql = string.Format("INSERT INTO [{2}]({0}) VALUES({1});", columnsList, paramsList, TableName);
 
                //создаем команду
                using (var command = new OleDbCommand(sql, conn))
                {
                    //инициализируем параметры значениями
                    foreach (var q in questionnaire)
                    {
                        var answer = anketa.FirstOrDefault(a => a.QuestId == q.Id);
                        var val = GetExportedAlternativeValue(q, answer);
                        command.Parameters.AddWithValue("@" + q.Id, val);
                    }
 
                    //исполняем SQL запрос
                    conn.Open();
                    command.ExecuteNonQuery();
                }
 
                conn.Close();
            }
        }


Добавлено через 1 минуту
Решил использовать одну форму для запуска разных опросников/внесения результатов в разные эксели.
0
16.11.2018, 19:29

Не по теме:

Наркоманов и личностей с синдромом заоблачного ЧСВ прошу отписаться от темы и прекратить тут постить ахинею, не нравится читать - вас никто не заставляет.

1
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
16.11.2018, 19:38  [ТС]
Цитата Сообщение от MIRAMIX Посмотреть сообщение
Все хорошо, можно спокойно передать готовые string, но вот не пойму как встроить мои данные в этот участок :
Ну так ConnectionString нужно сформировать правильным образом. Туда ваш путь сохранения и нужно встраивать.
А вот save_path в Export можно и не передавать.
1
#MRoose
 Аватар для MIRAMIX
8 / 9 / 3
Регистрация: 22.02.2013
Сообщений: 416
16.11.2018, 19:46
Цитата Сообщение от Storm23 Посмотреть сообщение
Ну так ConnectionString нужно сформировать правильным образом. Туда ваш путь сохранения и нужно встраивать.
это мелочь... проблема (непонимание) как в sql запросе из метода Export(...) передать еще другие значения для других столбцов(id, ФИО1, логин1, логин2, логин3), чтобы разом заполнить всю строчку в табличке

Добавлено через 3 минуты
Цитата Сообщение от Storm23 Посмотреть сообщение
А вот save_path в Export можно и не передавать.
забыл, я же уже это сделал) :
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
class ExportToDB
    {
        static string path;
        public string ConnectionString { get; set; } = @"Provider=Microsoft.ACE.OleDb.12.0; data source="+path+";Extended Properties=Excel 12.0";
        public string TableName { get; set; } = "Лист1$";
        public bool ExportAltTextInsteadOfCode { get; set; } = true;
 
        public void Export(Questionnaire questionnaire, Anketa anketa, string save_path)
        {
            path=save_path;


Передавать нужно (вроде?) так как формочка одна для многих экселей
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
16.11.2018, 21:24  [ТС]
Цитата Сообщение от MIRAMIX Посмотреть сообщение
я же уже это сделал
Ну я бы так варварски не делал.
Зачем вы ломаете класс ExportToDB? Он отличный. Его не нужно трогать.
Нужно просто его правильно использовать:

C#
1
2
3
var exporter = new ExportToDB();
exporter.ConnectionString = "....тут формируем нужную строку подключения....";
exporter.Export(questionnaire, anketa);
Вот и все, сам класс ExportToDB оставьте в покое, там все хорошо.
Ну разве что вы можете добавить метод Update, если нужно. Но не нужно туда передавать всякую гадость типа string save_path.
1
#MRoose
 Аватар для MIRAMIX
8 / 9 / 3
Регистрация: 22.02.2013
Сообщений: 416
16.11.2018, 21:38
Storm23, спасибо, изменю. Не спорю, класс отличный, как и все остальные из ядра)
Пожалуйста, помогите тогда подредактировать метод
C#
1
Export
, чтобы он не только значения опросника вставлял, но и другие столбцы заполнял (значения передам в при вызове)
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
16.11.2018, 23:11  [ТС]
Цитата Сообщение от MIRAMIX Посмотреть сообщение
чтобы он не только значения опросника вставлял, но и другие столбцы заполнял (значения передам в при вызове)
Полный код ExportToDB:
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.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
 
namespace QuestCoreNS
{
    /// <summary>
    /// Экспорт в базу данных
    /// </summary>
    public class ExportToDB
    {
        public string ConnectionString { get; set; } = @"Provider=Microsoft.ACE.OleDb.12.0; data source=C:\export.xlsx;Extended Properties=Excel 12.0";
        public string TableName { get; set; } = "Лист1$";
        public bool ExportAltTextInsteadOfCode { get; set; } = false;
 
        private const string ADD_PARAM_PREFIX = "@add";
 
        public void Export(Questionnaire questionnaire, Anketa anketa, List<Tuple<string, object>> additionalParameters = null)
        {
            using (var conn = new OleDbConnection(ConnectionString))
            {
                //формируем список колонок
                var columnsList = string.Join(", ", questionnaire.Select(q => q.Id));
 
                //имена колонок для дополнительных параметров
                if (additionalParameters != null)
                {
                    columnsList += ", " + string.Join(", ", additionalParameters.Select(p => p.Item1));
                    columnsList = columnsList.Trim(' ', ',');
                }
 
                //формируем список параметров
                var paramsList = string.Join(", ", questionnaire.Select(q => "@" + q.Id));
 
                //список доп параметров
                if (additionalParameters != null)
                {
                    paramsList += ", " + string.Join(", ", Enumerable.Range(0, additionalParameters.Count).Select(p=> ADD_PARAM_PREFIX + p));
                    paramsList = paramsList.Trim(' ', ',');
                }
 
                //формируем SQL запрос
                var sql = string.Format("INSERT INTO [{2}]({0}) VALUES({1});", columnsList, paramsList, TableName);
 
                //создаем команду
                using (var command = new OleDbCommand(sql, conn))
                {
                    //инициализируем параметры значениями
                    foreach (var q in questionnaire)
                    {
                        var answer = anketa.FirstOrDefault(a => a.QuestId == q.Id);
                        var val = GetExportedAlternativeValue(q, answer);
                        command.Parameters.AddWithValue("@" + q.Id, val);
                    }
 
                    //инициализируем доп параметры значениями
                    if(additionalParameters != null)
                    for (int i = 0; i < additionalParameters.Count; i++)
                    {
                        command.Parameters.AddWithValue(ADD_PARAM_PREFIX + i, additionalParameters[i].Item2);
                    }
 
                    //исполняем SQL запрос
                    conn.Open();
                    command.ExecuteNonQuery();
                }
 
                conn.Close();
            }
        }
 
        private object GetExportedAlternativeValue(Quest quest, Answer answer)
        {
            if (answer == null) return null;
 
            if (ExportAltTextInsteadOfCode)
            {
                if (answer.Text != null)
                    return answer.Text;
                var alt = quest.FirstOrDefault(a => a.Code == answer.AlternativeCode);
                return alt?.Title;
            }
            else
            {
                return answer.ToString();
            }
        }
    }
}
Пример вызова с доп параметрами:
C#
1
2
3
4
5
6
7
8
                    //формируем доп параметры
                    var addParams = new List<Tuple<string, object>>();
 
                    addParams.Add(new Tuple<string, object>("id", 777));
                    addParams.Add(new Tuple<string, object>("ФИО", "Бонд, Джеймс"));
 
                    //сохраняем анкету в БД
                    new ExportToDB().Export(questionnaire, anketa, addParams);
1
#MRoose
 Аватар для MIRAMIX
8 / 9 / 3
Регистрация: 22.02.2013
Сообщений: 416
16.11.2018, 23:46
Storm23, огромное спасибо, очень выручили

Добавлено через 30 минут

Не по теме:

Цитата Сообщение от Woldemar89 Посмотреть сообщение
Наркоманов и личностей с синдромом заоблачного ЧСВ прошу отписаться от темы и прекратить тут постить ахинею, не нравится читать - вас никто не заставляет.
надеюсь это не мне

0
TheGreatCornholio
 Аватар для Woldemar89
1255 / 733 / 285
Регистрация: 30.07.2015
Сообщений: 2,408
17.11.2018, 01:41
Цитата Сообщение от MIRAMIX Посмотреть сообщение
надеюсь это не мне
Разумеется, нет.
Еще совет:
Вам нужно понять почему именно так (как в теме) реализован алгоритм - следует вчитываться в каждую фразу\строку по несколько раз.
Таким образом, вы научитесь не просто копипастить код, а понять мысли (более опытного разработчика, разумеется).
Я не убеждаю и не настаиваю, - просто попробуйте, это очень помогает в развитии.
1
#MRoose
 Аватар для MIRAMIX
8 / 9 / 3
Регистрация: 22.02.2013
Сообщений: 416
17.11.2018, 02:12
Цитата Сообщение от Woldemar89 Посмотреть сообщение
Еще совет:
разумеется, абсолютно согласен с Вами, уже более менее начинаю понимать некоторые части ядра.

Когда свой проект доделаю (сейчас бошка разрывается от объема), задам кучу теоретических вопросов (в моей оригинальной теме+тут много интересных понятий написали), потом тоже хочу в продолжение этого FAQ еще свой написать
0
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
18.11.2018, 15:09
Здравствуйте всем. Посмотрел проект, скажу сразу - архитектура немного или непривычная либо запутанная. Для понимания связей приходится много раз скакать по контролам и думать что откуда приходит. Единственное, что мне понравилось, и что я возьму для себя - это класс Quest - он очень удобно сделан и им очень интересно пользоваться - тут и список сразу с вариантами и свойства сразу вопроса - признаюсь, не пользовался подобными конструкциями. Обработчик всех событий в одном месте - вещь взятая из MVP - тут говорить не о чем. Хотелось бы добавить вот что. Там, на каждом вопросе имеется "Если" - сама форма для записи Condition - мало что проясняет, да думаю - не очень ей удобно пользоваться. Я не успел сделать, уже когда свободное время ещё будет, но можно сделать выбор из уже имеющихся вопросов и в них из имеющихся вариантов - заготовку оставил, но уже позже немного - не могу представить всю модель, чтобы ничего не поломать и не изменить оригинальный подход автора, так как только сегодня погрузился в проект.
Непонятны следующие вещи - сортировка вопросов, сортировка вариантов - вообще зачем эти действия? Потом, условия для вариантов - вообще не понимаю, зачем тоже нужны. Исправил некоторые ошибки архитектуры и мелкие недочёты в бизнес обработке. Вот мой труд, что я сегодня поправил.

Вообще, я ещё тогда почему-то решил, что автор не добавил зависимость вопроса от выбора варианта, на что автор вроде как предложил это мне сделать, хотя, я вижу, что он это реализовал через Calculator и Condition. Особо не вижу тут действий - только если сделать удобнее установку зависимостей.

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

Может, где не хватает комментов, тут уж извините, стараюсь писать код так, чтобы было понятно без них.

Вообще, признаться, просто от скуки решил поковырять, вообще, если принимаете мои поправки, то думаю, что изменённый код на хабе даст мне знать, что я вообще не зря полез туда. Если не нужно, то тогда доделайте сами. В основном там рефакторинг остался.

Да, и по поводу генерирования всех элементов в Build по изменившемуся состоянию - не хочу никого обидеть, но этот генератор очень начинает тормозить уже на 15м вопросе и 15ой альтернативе в вопросе. Также для себя взял идею отмены прорисовки - реально работает.
Вложения
Тип файла: rar QuestConstructor-master2.rar (170.1 Кб, 30 просмотров)
0
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
18.11.2018, 15:13
Цитата Сообщение от Woldemar89 Посмотреть сообщение

Не по теме:

следует вчитываться в каждую фразу\строку по несколько раз

Не по теме:


что за идиотизм вы предлагаете? Повторение чтения одной и той же строки - ваш подход к изучению? Тогда интересно, действительно, кто из нас тут наркоман.

Просто пусть отладчиком пройдётся и всё.
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
18.11.2018, 16:31  [ТС]
Цитата Сообщение от umatkot Посмотреть сообщение
но можно сделать выбор из уже имеющихся вопросов и в них из имеющихся вариантов
Можно то можно, но учтите, что сейчас можно задавать произвольные выражения со скобками, арифметическими и условными операторами, логическими связками. А сможете ли вы сделать визуальный конструктор для поддержки таких выражений?
Цитата Сообщение от umatkot Посмотреть сообщение
Непонятны следующие вещи - сортировка вопросов, сортировка вариантов - вообще зачем эти действия?
Для изменения порядка вопросов/альтернатив, вставки новых вопросов/альтернатив.
Цитата Сообщение от umatkot Посмотреть сообщение
Потом, условия для вариантов - вообще не понимаю, зачем тоже нужны.
Для фильтрации альтернатив.
Допустим есть два вопроса:
1) Вы пьете пиво? (да/нет)
2) Какие товары вы больше всего любите? (конфеты/пиво/яблоки)

Понятно, что если респондент ответил в первом вопросе что он НЕ пьет пиво, то во втором вопросе нет смысла показывать альтернативу про пиво. Для этого используются фильтры альтернатив.

Ну и кроме того, необходимость фильтрации альтернатив было в исходном ТЗ.

Цитата Сообщение от umatkot Посмотреть сообщение
генератор очень начинает тормозить уже на 15м вопросе и 15ой альтернативе в вопросе
Он не рассчитан на большое число вопросов и альтернатив. Я делал самым простым способом. Если вопросов будет очень много - нужно либо использовать виртуальный режим, либо делать отдельно слева список вопросов, а справа - панель свойств вопроса. Но эти оба варианта существенно усложняют код, я их не делал.

umatkot, посмотрел ваш код. Какую задачу вы решаете?
Вы убрали зачем-то метод Build из главной формы, и теперь опросники просто не открываются. Зачем?
Вы добавили радиобаттоны и комбобоксы с непонятной функцией.
Что они должны делать?
0
131 / 146 / 19
Регистрация: 19.02.2017
Сообщений: 619
18.11.2018, 16:45
А правила не запрещают писать такие простыни? Это же не вопрос, а туториал.
0
TheGreatCornholio
 Аватар для Woldemar89
1255 / 733 / 285
Регистрация: 30.07.2015
Сообщений: 2,408
18.11.2018, 23:21
Цитата Сообщение от umatkot Посмотреть сообщение
что за идиотизм вы предлагаете? Повторение чтения одной и той же строки - ваш подход к изучению? Тогда интересно, действительно, кто из нас тут наркоман.
Спасибо, все сразу стало на свои места, это я - наркоман, - а Вы - Опытный Программист.
Извиняюсь за беспорядок. Постараюсь больше не мешать.
Этот пост не в счет, конечно же.
Создание программы - ООП модель, MVP
0
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
19.11.2018, 00:45
Storm23,
Цитата Сообщение от Storm23 Посмотреть сообщение
но учтите, что сейчас можно задавать произвольные выражения со скобками, арифметическими и условными операторами, логическими связками
А можно пример? Вообще-то я не совсем понимаю, зачем такие сложности?

Цитата Сообщение от Storm23 Посмотреть сообщение
Допустим есть два вопроса:
1) Вы пьете пиво? (да/нет)
2) Какие товары вы больше всего любите? (конфеты/пиво/яблоки)
Понятно, что если респондент ответил в первом вопросе что он НЕ пьет пиво, то во втором вопросе нет смысла показывать альтернативу про пиво. Для этого используются фильтры альтернатив.
Неудачный пример немного, но я понял. Только если вот так, например, что в первом вопросе респондент отвечает про пиво, то следующий вопрос, который содержит Condition вопроса и варианта уже не будет содержать вариантов с пивом - тут можно создать два вопроса, каждый условно будет ссылаться на тех, кто пьёт пиво и на тех, кто не пьёт и вести параллельно две ветки вариантов уже для каждой категории. Но я понял, что так экономится количество вопросов и что на дальнейших вопросах можно делать пересечения с выбором.

Цитата Сообщение от Storm23 Посмотреть сообщение
Я делал самым простым способом
Посмотрите, пожалуйста, как я поправил и сравните.

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

Добавлено через 8 минут
Storm23, там ещё момент какой-то мутный в дизайнере - сам UserControl с вопросом начинает расширяться, если начинать добавлять альтернативу. Там, в дизайнере, якоря стоят то на правую сторону, то на левую - изменяешь размер QuestPanel и внутри контролы ползут друг на друга.

Добавлено через 16 минут
Цитата Сообщение от Storm23 Посмотреть сообщение
комбобоксы с непонятной функцией
про комбобоксы я объяснил, что можно сделать в них вывод имеющихся вопросов - так просто проще для пользователя определять зависимые вопросы от добавленных вариантов - я не успел.
Про форму выражений - это замечательно, что она как умный калькулятор, но если уже туда добавлена портянка из ресурсов в виде микромануала, то я вот с первого взгляда не определил, что там и как составлять - надо ковырять код и смотреть тесты.

Цитата Сообщение от Storm23 Посмотреть сообщение
Вы убрали зачем-то метод Build из главной формы
Да, я его изменил. Поясняю - я переработал некоторые моменты.
Код в Build, который делал вот это(оставил с комментариями)
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void Build()
        {
            //очищаем центральную панель
            //pnMain.Controls.Clear();
 
            //создаем контролы для каждого вопроса
            //foreach (var quest in _questionnaire)
            //{
                
 
                
            //}
 
            //обновляем интерфейс
            UpdateInterface();
        }


Я поменял на вот это:
Подписка на события
Кликните здесь для просмотра всего текста
C#
1
pn.QuestionnaireListChanged += ProcessQuestionListAction;


Тело делегата тоже изменил
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
private void ProcessQuestionListAction(string questionPanelKey, UserPanelActionType actionType)
        {
            FlowPanelActionHelper.ProcessElements(questionPanelKey, actionType);
            _changed = true;//выставлем флажок изменения
        }


Так как у вас повторяются действия по двум моментам с FlowPanel я решился добавить общий обработчк на оба случая.
Кликните здесь для просмотра всего текста
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
public class FlowPanelActionHelper
    {
        private FlowLayoutPanel FlowLayoutPanel { get; }
 
        public FlowPanelActionHelper(FlowLayoutPanel flowLayoutPanel)
        {
            FlowLayoutPanel = flowLayoutPanel;
        }
        
        /// <summary>
        /// Управление пользовательскими элементами управления внутри FlowLayoutControl
        /// </summary>
        /// <param name="elementKey">Ключ элемента управления</param>
        /// <param name="actionType">Тип действия над элементом управления</param>
        public void ProcessElements(string elementKey, UserPanelActionType actionType)
        {
 
            switch (actionType)
            {
                case UserPanelActionType.Remove:
                    FlowLayoutPanel.Controls.RemoveByKey(elementKey);
                    break;
                case UserPanelActionType.MoveUp:
                case UserPanelActionType.MoveDown:
                    //создаем хелпер отрисовки, останавливаем отрисовку
                    var helper = new ControlHelper(FlowLayoutPanel);
                    var movingAlt = FlowLayoutPanel.Controls.Find(elementKey, false).First();
                    if (movingAlt == null) break;
 
                    var controlIndex = FlowLayoutPanel.Controls.IndexOfKey(elementKey);
 
                    /*ограничение на циклическую перестановку пользовательских элементов управления внутри FlowLayoutControl*/
                    if (controlIndex == 0 && actionType == UserPanelActionType.MoveUp) break;
 
                    FlowLayoutPanel.Controls.SetChildIndex(movingAlt, controlIndex + (int)actionType);
                    helper.ResumeDrawing();
                    break;
            }
            
        }
    }


Мне эта реализация нравится намного больше вашей, поэтому я позволил себе такие выходки. Да и используется это намного удобнее, чем постоянная перерисовка элементов управления с нуля. Да и сложности в самом коде я не встретил при реализации - сам FlowLayoutPanel диктовал мне путь))) Я ещё хотел сделать вообще наследуемые UserControl от этого класса, чтобы иметь внутри формы свои методы обработки, но потом осёкся, так как нужно было делать статичную передачу FlowLayoutPanel в базовый класс, для этого бы мне в самом Designer проставить везде static у FlowLayoutPanel - что является бредом. Да и не унаследуешь сразу и форму и UserControl от UserControl....
0
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
19.11.2018, 00:47
Убрал комбобоксы
Вложения
Тип файла: rar QuestConstructor-master2.rar (96.9 Кб, 34 просмотров)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.11.2018, 00:47
Помогаю со студенческими работами здесь

Модель ООП
Помоги сделать, пожалуйста работу! Возможно у кого нибудь есть примеры работы с классами! БУду рада всему, что есть! У меня тема...

Закрепить модель ООП
Добрый день. Ситуация такая: Я знаю и представляю себе модель ООП, классы, объекты, наследование и т.д. Но так как до чисто...

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

ООП модель системы спама
Срочно нужна помощь! Помогите пожалуйста реализовать программу с помощью классов. Спамер рассылает по сети Internet недобросовестную...

Ооп модель телефонного справочника
Нужен код на тему в заголовке с добавлением классов.Га с++ Буду очень благодарна!!


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Опции темы

Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru