Таким образом, после того, как некоторые исследования на основе вышеуказанных ответов, далее Google поиска и просят коллегу, который знает немного о C# мой выбранное решение проблемы ниже. Я по-прежнему интересуюсь комментариями, предложениями и уточнениями.
Прежде всего, мы расскажем о проблеме, которая на самом деле довольно типична в том смысле, что GUI контролирует что-то, что должно оставаться полностью абстрактным, посредством серии событий, ответы на которые GUI должен реагировать. Там есть несколько отдельных проблем:
- События сами по себе, с разными типами данных. События будут добавлены, удалены, изменены по мере развития программы.
- Как подключить несколько классов, которые составляют GUI (разные UserControls), и классы, которые абстрагируют аппаратное обеспечение.
- Все классы могут производить и потреблять события и должны оставаться развязанными, насколько это возможно.
- Компилятор должен определить кодирование cockups, насколько это возможно (например, событие, которое посылает один тип данных, но comsumer, что ожидает другой)
Первая часть этого события. Поскольку графический интерфейс и устройство могут создавать несколько событий, возможно, связанных с ними разными типами данных, диспетчер событий удобен.Это должно быть общим в обеих событиях и данных, так:
// Define a type independent class to contain event data
public class EventArgs<T> : EventArgs
{
public EventArgs(T value)
{
m_value = value;
}
private T m_value;
public T Value
{
get { return m_value; }
}
}
// Create a type independent event handler to maintain a list of events.
public static class EventDispatcher<TEvent> where TEvent : new()
{
static Dictionary<TEvent, EventHandler> Events = new Dictionary<TEvent, EventHandler>();
// Add a new event to the list of events.
static public void CreateEvent(TEvent Event)
{
Events.Add(Event, new EventHandler((s, e) =>
{
// Insert possible default action here, done every time the event is fired.
}));
}
// Add a subscriber to the given event, the Handler will be called when the event is triggered.
static public void Subscribe(TEvent Event, EventHandler Handler)
{
Events[Event] += Handler;
}
// Trigger the event. Call all handlers of this event.
static public void Fire(TEvent Event, object sender, EventArgs Data)
{
if (Events[Event] != null)
Events[Event](sender, Data);
}
}
Теперь нам нужны некоторые события и ближайший из мира C, мне нравится перечисления, поэтому я определить некоторые события, что графический интерфейс поднимет:
public enum DEVICE_ACTION_REQUEST
{
LoadStuffFromXMLFile,
StoreStuffToDevice,
VerifyStuffOnDevice,
etc
}
Теперь в любом месте в пределах объема (пространство имен, как правило) статического класс EventDispatcher, то можно определить новый диспетчер:
public void Initialize()
{
foreach (DEVICE_ACTION_REQUEST Action in Enum.GetValues(typeof(DEVICE_ACTION_REQUEST)))
EventDispatcher<DEVICE_ACTION_REQUEST>.CreateEvent(Action);
}
Это создает обработчик события для каждого события в ванной гм.
И потребляются, подписавшись на события, как этот код в конструкторе потребляющего объекта Device:
public DeviceController()
{
EventDispatcher<DEVICE_ACTION_REQUEST>.Subscribe(DEVICE_ACTION_REQUEST.LoadAxisDefaults, (s, e) =>
{
InControlThread.Invoke(this,() =>
{
ReadConfigXML(s, (EventArgs<string>)e);
});
});
}
Где InControlThread.Invoke это абстрактный класс, который просто оборачивает вызов Invoke.
Событие может быть поднято GUI просто:
private void buttonLoad_Click(object sender, EventArgs e)
{
string Filename = @"c:\test.xml";
EventDispatcher<DEVICE_ACTION_REQUEST>.Fire(DEVICE_ACTION_REQUEST.LoadStuffFromXMLFile, sender, new EventArgs<string>(Filename));
}
Это имеет то преимущество, что если событие поднимая и потребляющие типов не совпадает (здесь строки файла) компилятор будет ворчать.
Существует множество улучшений, которые могут быть сделаны, но это гайки проблемы. Мне было бы интересно, как я сказал в комментариях, особенно если есть какие-либо вопиющие упущения/ошибки или недостатки. Надеюсь, это поможет кому-то.
Это, наверное, самый простой способ, и он хорошо работает в начале, и я использовал его раньше, но у него есть тот недостаток, что после того, как графический интерфейс становится больше и состоит из большего количества классов или UserControls (что неизбежно происходит), что он плохо масштабируется. Возможно, я должен был указать в своем вопросе, что причина, по которой я ищу универсальное решение, я полностью ожидаю, что это приложение будет расти со временем и будет хотеть что-то, что масштабируется. – 0xDEADBEEF