Следствие того, что написал Антон, состоит в том, что , если элемент управления не привязан к источнику данных, который выдает уведомления об изменениях, у вас есть для подключения события для каждого элемента управления. Различные элементы управления имеют разные наборы свойств, которые могут изменяться, и иногда может иметь значение более одного из них, в зависимости от того, как вы разработали свой пользовательский интерфейс.
У меня есть несколько похожих приложений, и один из шаблонов, которые мне нравится использовать, - это «служба событий». Вы можете использовать контейнер IoC, чтобы связать все, и основным формам / подзадачам никогда не нужно будет напрямую общаться друг с другом.
Интерфейс выглядит следующим образом:
public interface IEventService
{
void RaiseChanged(object sender, EventArgs e);
event EventHandler Changed;
}
Базовая реализация довольно проста, но я все равно ее включу:
public class EventService : IEventService
{
public void RaiseChanged(object sender, EventArgs e)
{
EventHandler handler = Changed;
if (handler != null)
handler(sender, e);
}
public event EventHandler Changed;
}
Определите его в выбранном вами контейнере IoC и настройте его так, чтобы он вел себя как синглтон, или просто внедрите его как синглтон, если IoC будет слишком много работы; Я предполагаю, что вы идете с первым вариантом. Тогда ваш основной код формы выглядит так:
public class MainForm : Form
{
private bool currentTaskChanged;
public MainForm()
{
InitializeComponent();
InitializeChangeEvents();
}
public void LoadTask(ITask task)
{
if (currentTaskChanged)
{
// Confirm whether or not to save changes
}
// Code to change the current task view here ...
currentTaskChanged = false;
}
private void InitializedChangedEvents()
{
IEventService service = IoC.Resolve<IEventService>();
service.Changed += TaskChanged;
}
private void TaskChanged(object sender, EventArgs e)
{
currentTaskChanged = true;
}
}
Тогда довольно просто зачислить новые подзадачи / элементы управления:
public class CustomerSetupControl : UserControl
{
public CustomerSetupControl()
{
InitializeComponent();
InitializeChangeTriggers();
}
private void InitializeChangeTriggers()
{
IEventService service = IoC.Resolve<IEventService>();
txtAccountNumber.TextChanged += service.RaiseChanged;
txtName.TextChanged += service.RaiseChanged;
chkIsVip.CheckedChanged += service.RaiseChanged;
// etc.
}
}
Вы можете теоретически автоматизировать некоторые из них, перебирая все дерево управления подзадачей, но это довольно сложно. Например, если одним из элементов управления является CheckBox
, перехват события TextChanged
действительно не поможет вам. Таким образом, вам нужно сделать это один за другим, чтобы убедиться, что вы действительно обнаруживаете правильное измененное событие для правильного элемента управления, а в некоторых случаях вы можете даже игнорировать изменения определенного элемента управления (т. Е. Возможно, есть поле со списком, которое просто меняет фильтр где-то без изменения каких-либо данных).
Это не точно код, который я использую, но он очень похож. Я предлагаю попробовать это; поскольку я нахожу, что это не так уж сложно поддерживать, вам просто нужно помнить, чтобы "регистрировать" новые элементы управления при их добавлении.
Что особенно приятно в этом подходе, так это то, что любой элемент управления может зарегистрироваться в службе событий; вы можете легко расширить службу, включив в нее различные типы «общедоступных» событий, которые можно использовать в любом месте приложения (просто не забудьте отменить регистрацию обработчиков событий в любых элементах управления, которые не живут вечно, как в основной форме).