Распространенным способом решения этой проблемы является отделение кода, отправляющего предупреждение, от кода, который отображает предупреждение.
Для начала вам следует создать класс, единственная цель которого - передать его.при обновлении любого пользовательского интерфейса.
public class MessageUpdater
{
public event EventHandler<string> MessageSent;
public void SendMessage(string message)
{
this.MessageSent?.Invoke(this, message);
}
}
Это очень просто.Он просто принимает сообщение и, если к событию присоединены обработчики, он вызывает событие.
Теперь для вашего AlertBox
вы просто принимаете экземпляр MessageUpdater
и обновляете Label
всякий раз, когда MessageSent
событие инициируется.
public partial class AlertBox : Form
{
public AlertBox()
{
InitializeComponent();
}
private MessageUpdater _messageUpdater = null;
public MessageUpdater MessageUpdater
{
set
{
if (_messageUpdater != null)
{
_messageUpdater.MessageSent -= UpdateMessage;
}
if (value != null)
{
_messageUpdater = value;
_messageUpdater.MessageSent += UpdateMessage;
}
}
}
private void UpdateMessage(object sender, string message)
{
if (this.InvokeRequired)
{
this.Invoke((Action)(() => this.UpdateMessage(sender, message)));
}
else
{
this.MessageLabel.Text = message;
}
}
}
Две хитрые части здесь обрабатывают присоединение нового MessageUpdater
(и удаление существующего), а затем маршалинг вызовов в поток пользовательского интерфейса, если это необходимо.
Код, который я создал, чтобы проверить это, был довольно прост.
var mu = new MessageUpdater();
var counter = 0;
var timer = new System.Threading.Timer((System.Threading.TimerCallback)(x =>
{
mu.SendMessage((counter++).ToString());
}), null, TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0));
var ab = new AlertBox();
ab.MessageUpdater = mu;
ab.ShowDialog();
Хитрая часть здесь - это System.Threading.Timer
, который я использовал для отправки сообщений на MessageUpdater
в потоке без пользовательского интерфейса , чтобы .ShowDialog
не зависал.