Я бы посоветовал вам узнать про dependency injection. С использованием его все становится гораздо проще.
Приведу пример организации проекта:
1 Модуль описание интерфейсов для работы
interface ICore {...}
interface IDeviceManager {...}
у этого модуля не должно быть зависимостей
я думаю в нем же можно объявить структуры данных, но у них так же не должны быть зависимостей от других модулей программы
2 Модуль ядро - в нем должна быть реализована вся логика работы с приборами(или еще чем то) как сервис
class Core : ICore {...}
class DeviceManager : IDeviceManager{...}
этот модуль в зависимостях должен иметь только модуль 1
он должен быть автономным - работать в потоках
3 Модуль Gui - здесь есть варианты, но объединяет их одно - использование шаблона проектирование "внедрение зависимостей". Вот
сравнение контейнеров. Я использую LightInject он быстр и прост.
Метод запуска окошек с контейнером на примере LightInject.
допустим у вас есть главное окно и окно с приборами
public partial class MyMainForm
{
private LightInject.IServiceContainer _container;
public MyMainForm(LightInject.IServiceContainer container)
{
_container = container;
}
public void ShowDeviceWindow()
{
var form = _container.Create<MyDeviceForm>();
form.Show();
}
}
public partial class MyDeviceForm
{
private IDeviceManager _deviceManager;
public MyDeviceForm(IDeviceManager devicemanager)
{
_deviceManager = devicemanager;
}
public void ButtonClick()
{
// Здесь вы делаете все что хотите и работаете с менеджером
// Например загружаете список приборов в лист
foreach(var device in _deviceManager.GetDevices())
listBox.Add(device.ToString());
}
для того что бы не создавать все объекты и зависимости окнам руками используем контейнер
если вы используете WinForms то скорее всего это надо прописать в programm.cs
var container = new LightInject.ServiceContainer();
container.RegisterInstance<IServiceContainer>(container);
container.Register<ICore, Core>(new PerContainerLifetime());
container.Register<IDeviceManager, DeviceManager>(new PerContainerLifetime());
var form = container.Create<MyMainForm>();
//Не помню как выводятся окна в WinForms
//Но логика надеюсь понятна
form.Show();
Таким образом у нас любое окно может запросить любой нужный ему интерфейс для работы с ядром\логикой.
Что бы в каждое окно не совать IServiceContainer я бы создал IWindowManager в реализации которой получал бы контейнер и выводил окно что то вроде
manager.ShowWindow<MyDeviceForm>();
и всем окнам подсовывал бы его. Так проще контролировать создание окон.
Для WPF я бы мог посоветовать глянуть различным MVVM фрейворки
Calibrun.Micro,
Catel и тд.
Есть даже модульная система выглядящая как IDE
gemini
Не знаю чем обусловлен выбор WinForms, но для него тоже есть фреймворки, но вроде бы в них применяется шаблон MVP.
Для своих нужд я написал клон
gemini со своим видением некоторых моментов. Надеюсь это поможет в разделение логики и окон, несколько лет назад я так же искал информацию как же вообще строить окна, но подсказать было некому.
PS: код набирал в текстовом редакторе, могут быть опечатки и неточности.