Как я могу захватить события из суб-элементов управления пользователя в приложении WinForms?
Есть ли способ, чтобы основная форма могла перехватывать события, запускающие субконтроль в пользовательском элементе управления?
У меня есть пользовательский элемент управления, встроенный в основную форму моего приложения. Элемент управления содержит различные субконтроллеры, которые управляют данными, которые сами отображаются другими элементами управления в основной форме. Я бы хотел, чтобы основная форма могла быть каким-то образом проинформирована, когда пользователь меняет субконтроллеры, поэтому я мог обновлять данные и соответствующий экран в другом месте.
Сейчас я обманываю. У меня есть делегат, подключенный к фокусу-событию субконтроля. Этот делегат изменяет свойство пользовательского элемента управления, которое я не использую в другом месте (в этой причине CausesValidation). Затем у меня есть делегат, определенный в основной форме, когда изменяется свойство CausesValidation элемента управления пользователя, которое затем направляет приложение для обновления данных и отображения.
Проблема возникает из-за того, что у меня также есть набор делегатов, когда фокус покидает пользовательский контроль, потому что мне нужно проверить поля в пользовательском элементе управления, прежде чем я смогу позволить пользователю делать что-либо еще. Однако, если пользователь просто переключается между субконтролями, я не хочу проверять, потому что они могут не выполняться.
В принципе, я хочу, чтобы данные обновлялись, когда пользователь переключает субконтроллеры или выходит из пользовательского элемента управления, но не проверяет. Когда пользователь покидает элемент управления, я хочу обновить и проверить. Прямо сейчас, оставляя контроль пользователя, вызывает проверку дважды.
Ответы
Ответ 1
Лучшей практикой было бы вывести события на UserControl
, которые пузырят события до родительской формы. Я пошел вперед и собрал для вас пример. Вот описание того, что предоставляет этот пример.
-
UserControl1
- Создайте
UserControl
с помощью TextBox1
- Зарегистрируйте публичное событие на
UserControl
, называемом ControlChanged
- Внутри регистра
UserControl
обработчик события для TextBox1
TextChangedEvent
- В функции обработчика
TextChangeEvent
я вызываю событие ControlChanged
для создания пузырьков в родительскую форму
-
Form1
- Отбросить экземпляр
UserControl1
в конструкторе
- Зарегистрируйте обработчик событий на
UserControl1
для MouseLeave
и для ControlChanged
Вот скриншот, иллюстрирующий, что событие ControlChanged
, которое я определил в UserControl
, доступно через UX в Visual Studio в родительской форме Windows.
Обработчики событий для пользовательского контроля http://friendfeed.s3.amazonaws.com/0d5a3968cb785625c8afb3974a8d84894c476291
Ответ 2
Лучшая модель для такого рода вещей будет создавать пользовательские события в вашем пользовательском элементе управления и поднять их в соответствующее время.
Ваш сценарий довольно сложный, но не неслыханный. (Я нахожусь в очень похожем режиме в одном из моих текущих проектов.) Способ, которым я к нему подхожу, заключается в том, что пользовательский контроль отвечает за собственную проверку. Я не использую CausesValidation; вместо этого в соответствующей контрольной точке пользователя я выполняю проверку с помощью переопределения ValidateChildren(). (Обычно это происходит, когда пользователь нажимает "Сохранить" или "Далее" в пользовательском элементе управления для меня.)
Не знакомы с пользовательским интерфейсом пользовательского контроля, который не может быть на 100% правильным для вас. Однако, если вы поднимаете пользовательские события (возможно, с помощью специального EventArgs, который указывает, выполнять ли валидацию или нет), вы должны иметь возможность получить, где вы хотите быть.
Ответ 3
Вам нужно будет связать события, которые вам интересны при захвате внутри пользовательского элемента управления, и опубликовать их через некоторые настраиваемые свойства событий в самом пользовательском элементе управления. Простым примером будет обертка события нажатия кнопки:
// CustomControl.cs
// Assumes a Button 'myButton' has been added through the designer
// we need a delegate definition to type our event
public delegate void ButtonClickHandler(object sender, EventArgs e);
// declare the public event that other classes can subscribe to
public event ButtonClickHandler ButtonClickEvent;
// wire up the internal button click event to trigger our custom event
this.myButton.Click += new System.EventHandler(this.myButton_Click);
public void myButton_Click(object sender, EventArgs e)
{
if (ButtonClickEvent != null)
{
ButtonClickEvent(sender, e);
}
}
Затем в форме, которая использует этот элемент управления, вы подключаете событие так же, как и любое другое:
// CustomForm.cs
// Assumes a CustomControl 'myCustomControl' has been added through the desinger
this.myCustomControl.ButtonClickEvent += new System.EventHandler(this.myCustomControl_ButtonClickEvent);
myCustomControl_ButtonClickEvent(object sender, EventArgs e)
{
// do something with the newly bubbled event
}
Ответ 4
В случае, если кому-то все еще интересно, как имитировать пузырьки событий в WinForm, метод Application.AddMessageFilter - это хорошее место для просмотра.
С помощью этого метода вы можете установить свой собственный фильтр, который отслеживает все сообщения в текущей очереди сообщений потока.
Вы должны знать, что сообщения, отправленные (не отправленные), не могут обрабатываться этим фильтром. В целом, наиболее интересные события (например, события кликов) публикуются и не отправляются и, следовательно, могут контролироваться этим фильтром
Ответ 5
Я хотел бы перезвонить, поскольку, как описано, на самом деле это звучит так, будто вы преследуете красную селедку. Хотя кажется, что у вас есть ситуация, когда отсутствие пузырьков событий в WinForms вызывает у вас проблемы, реальность такова, что плохая архитектура вынуждает вас взывать пузырьки событий, когда вы этого не сделаете.
Если вы можете реорганизовать/реорганизовать свой дизайн таким образом, чтобы элементы управления работали с общей моделью данных (MVC/MVP - очевидные варианты), вы можете просто применить обычные шаблоны WinForms, такие как события PropertyChanged на модели, чтобы сообщить основную форму и любые другие элементы управления, которые используют эти данные для обновления.
Короче говоря, другие ответы разумны, поскольку они отвечают на заданный вопрос. Но с точки зрения качества кода, я думаю, лучший ответ - отделить ваши данные от пользовательского интерфейса.