Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/313: Рейтинг темы: голосов - 313, средняя оценка - 4.52
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34

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

30.10.2018, 11:10. Показов 72725. Ответов 100

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

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

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

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

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

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

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

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

Результаты опроса должны выгружаться в виде, пригодном для дальнейшей обработки.
19
Лучшие ответы (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,...

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

100
#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
10428 / 5158 / 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
10428 / 5158 / 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
10428 / 5158 / 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
10428 / 5158 / 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
10428 / 5158 / 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
Ответ Создать тему
Новые блоги и статьи
Debian 13: Установка Lazarus QT5
ВитГо 09.05.2026
Эта инструкция моя компиляция инструкций volvo https:/ / www. cyberforum. ru/ blogs/ 203668/ 10753. html и его же старой инструкции по установке Lazarus с gtk2. . .
Нейросеть на алгоритме "эстафета хвоста" как перспектива.
Hrethgir 06.05.2026
На десерт, когда запущу сервер. Статья тут https:/ / habr. com/ ru/ articles/ 1030914/ . Автор я сам, нейросеть только помогает в вопросах которые мне не известны - не знаю людей которые знали-бы. . .
Асинхронный приём данных из COM-порта
Argus19 01.05.2026
Асинхронный приём данных из COM-порта Купил на aliexpress термопринтер QR701. Он оказался странным. Поключил к Arduino Nano. Был очень удивлён. Наотрез отказывается печатать русские буквы. Чтобы. . .
попытка написать игровой сервер на C++
pyirrlicht 29.04.2026
попытка написать игровой сервер на плюсах с открытым бесконечным миром. возможно получится прикрутить интерпретатор питон для кастомизации игровой логики. что есть на текущий момент:. . .
Контроль уникальности выбранного документа-основания при изменении реквизита
Maks 28.04.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРемонтСпецтехники", разработанного в КА2. Задача: уведомлять пользователя, если указанная заявка (документ-основание). . .
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru