Я должен сказать, что это немного регрессия.В вашем предыдущем вопросе ДжошПарт дал вам хороший совет в виде пользовательских элементов управления, хотя, возможно, он оставил некоторые пробелы слишком большими, чтобы вы могли их заполнить самостоятельно.
Использование массивов в этомманера может работать в течение одного дня, но она не будет хорошо масштабироваться до полной недели.
Если кому-то, кто читает это, интересно, почему я говорю о полной неделе, я отсылаю вас к предыдущий вопрос .Кроме того, я признаю, что ухожу не по теме для этого конкретного вопроса, но я считаю, что это проблема XY, и предыдущий вопрос был фактически основан на реальной проблеме и работе, которая была более актуальной.
Давайте начнем с того, что мы знаем.Я получил это из двух вопросов и различных комментариев в обоих.
У вас есть DateTimePicker
элементы управления для начала, конца и обеда.Вас интересует только часть времени, поэтому для Format
установлено значение «Пользовательский», а для CustomFormat
установлено значение «ЧЧ: мм». Предположение: обед - фиксированная длина, поэтому время окончания не требуется.
У вас есть вышеупомянутые элементы управления умножить на семь , один комплектдля каждого дня недели.
Вы написали код проверки (диапазонные тесты), чтобы определить, правильно ли введены значения, и вы можете показать метку с красными восклицательными знакамикогда этот тест не пройден.
Вы определили, что становится слишком сложно, просто имея несколько элементов управления в форме.
Пока что, настолько хорошо.Теперь для вашей цели.
- Вы ищете способ упорядочить элементы управления и собираемые ими данные, чтобы упростить работу с ними.
A пользовательский контроль - все еще путь сюда.Вы получите выгоду от инкапсуляции всех этих повторяющихся функций в одном месте и возможности их повторного использования.
Начните с создания пользовательского элемента управления - мы назовем его DayPanel
-- и поместите все элементы управления на один день на этом холсте.Назовите элементы управления без учета дня недели (например, start
, lunch
и end
).Ваш пользовательский элемент управления не будет ни знать, ни заботиться о том, какой день он представляет.
Добавить обработчик события для ValueChanged
в элементы управления DateTimePicker.Вместо двойного щелчка по элементу управления перейдите к списку событий в окне инструмента «Свойства» и введите имя, например, приведенное ниже, для события ValueChanged
.Сделайте то же самое для двух других элементов управления, и он будет использовать обработчик событий, который он создал в первый раз.Всякий раз, когда пользователь изменяет время, будет вызываться этот обработчик событий, и он будет влиять на изменения пользовательского интерфейса.
private void picker_ValueChanged(object sender, EventArgs e)
{
// In case you need to know which DateTimePicker was changed, take a look at 'sender':
//DateTimePicker picker = (DateTimePicker)sender;
UpdateWarningState();
}
Как упоминал Джими, объект sender
будет ссылкой на элемент управления DateTimePicker, который отправилсобытие.Вам, вероятно, это не понадобится, но оно есть, если вы это сделаете.
UpdateWarningState
просто скрывает / показывает метку предупреждения в зависимости от достоверности введенных данных.
private void UpdateWarningState()
{
warningLabel.Visible = !IsInputValid(start.Value.TimeOfDay, lunch.Value.TimeOfDay, end.Value.TimeOfDay);
}
Я предложилв комментариях к предыдущему вопросу о том, что, по-видимому, имеет смысл получить true
, если входные данные верны, а затем использовать логический минус для видимости метки предупреждения.
Как отметил Пол Хеберт, вы действительнонужно только сравнить TimeSpan
, поэтому IsInputValid
получает свойство TimeOfDay
, чтобы иметь дело только с этим.
private bool IsInputValid(TimeSpan startTime, TimeSpan lunchTime, TimeSpan endTime)
{
return startTime < lunchTime && lunchTime.Add(TimeSpan.FromMinutes(30)) < endTime;
}
На самом деле, даже если вы вводите только время, элемент управленияпо-прежнему возвращает часть даты в свойстве Value
.Если вы хотите быть уверены, что вы не сравниваете время в разные даты, вам обязательно нужно использовать свойство TimeOfDay
.Тем не менее, не представляя часть даты, у вас есть мера контроля над этим, так что это не насущная проблема.Если вам придется беспокоиться о переходе через полночь, это может усложнить ситуацию.
Обратите внимание, что я имел дело с тем более ранним предположением, что обед является фиксированной продолжительностью, добавив 30 минут в сравнении с временем окончания.
Почему бы просто не сделать все это в обработчике событий ValueChanged
?
Принцип единой ответственности.IsInputValid
делает одно: бизнес-логика;он говорит вам, если входные данные действительны на основе тестирования диапазона.UpdateWarningState
делает другое: логика пользовательского интерфейса;он обновляет видимость метки предупреждения в зависимости от достоверности введенных данных.
UpdateWarningState
можно использовать повторно.Вы можете вызвать его из других обработчиков событий в будущем.Обработчики событий действительно не должны ничего делать.Они больше похожи на телефонных операторов: «Как я могу направить ваш звонок?»
IsInputValid
многоразового использования.Бизнес-логика может быть извлечена из вашего кода пользовательского интерфейса в будущем и может быть использована другим.Я признаю, что имя оставляет желать лучшего;он подходит здесь, но, вероятно, должен быть другим вне этого контекста.
Но что хорошего в этом пользовательском контроле, если у вас нет способа работать с его данными?Потребитель должен иметь возможность взаимодействовать с ним.Пользовательский элемент управления - это просто еще один класс, поэтому вы можете определять общедоступные свойства, методы и события по своему усмотрению.Мы добавим свойства для трех интересующих нас значений:
public TimeSpan Start
{
get => start.Value.TimeOfDay;
set => start.Value = start.Value.Date + value;
}
public TimeSpan Lunch
{
get => lunch.Value.TimeOfDay;
set => lunch.Value = lunch.Value.Date + value;
}
public TimeSpan End
{
get => end.Value.TimeOfDay;
set => end.Value = end.Value.Date + value;
}
Что интересно отметить, эти свойства не имеют собственного резервного хранилища.Вместо этого они переходят к элементам управления и переводят между своим собственным типом данных TimeSpan
и типом данных DateTime
элементов управления.На get
они возвращают только свойство TimeOfDay
.На set
они удаляют часть времени (с .Date
) и добавляют время суток.
Если вы строите это для кого-то другого, вы захотите убедиться, чтосвойство Days
равно 0
и что все значение неотрицательно, и либо бросьте ArgumentOutOfRangeException
, либо (задохнитесь!) ограничить значение до приемлемого диапазона.
Теперь, когда выиметь функциональный контроль в течение одного дня, вы можете шлепнуть их несколько в основной форме.Вернувшись в Form1
, добавьте семь экземпляров элемента управления DayPanel
и назовите их от monday
до sunday
.Прежде чем мы приступим к инициализации, давайте создадим поиск для этих пользовательских элементов управления.
private readonly Dictionary<DayOfWeek, DayPanel> _dayPanelLookup;
public Form1()
{
InitializeComponent();
_dayPanelLookup = new Dictionary<DayOfWeek, DayPanel>()
{
[DayOfWeek.Monday] = monday,
[DayOfWeek.Tuesday] = tuesday,
[DayOfWeek.Wednesday] = wednesday,
[DayOfWeek.Thursday] = thursday,
[DayOfWeek.Friday] = friday,
[DayOfWeek.Saturday] = saturday,
[DayOfWeek.Sunday] = sunday
};
}
Теперь обработчик Load
может инициализировать все свойства.Это DefaultTime
дублирует константу TimeSpan.Zero
с целью придания ей особого значения и может помочь в дальнейшем рефакторинге.
private static readonly TimeSpan DefaultTime = TimeSpan.Zero;
private void Form1_Load(object sender, EventArgs e)
{
SetDefaults();
}
private void SetDefaults()
{
foreach (DayPanel dayPanel in _dayPanelLookup.Values)
{
dayPanel.Start = DefaultTime;
dayPanel.Lunch = DefaultTime;
dayPanel.End = DefaultTime;
}
}
И просто для забавы, мы можем использовать _dayPanelLookup
, чтобы взять одиниз них на основе переменной, содержащей день недели.
public void someButton_Click(object sender,
{
DayOfWeek whichDay = SelectADay();
DayPanel dayPanel = _dayPanelLookup[whichDay];
// ...
}
Это должно решить основную проблему организации элементов управления и облегчения работы с ними и их значениями.То, что вы делаете с ним, когда пользователь нажимает какую-то еще неопознанную кнопку в форме, - это совершенно новое приключение.
Я уверен, что есть еще лучшие способы сделать все это.Я не разработчик пользовательского интерфейса, я просто играю по телевизору.Надеюсь, что для ваших целей это не только даст вам руководство, в котором вы нуждались на данном этапе в этом проекте, но и осветит новые возможности для размышления о том, как структурировать ваши программы в будущем.