Организация кода пользовательского интерфейса в формах .NET
Я тот, кто научил себя программированию и не имел никакого официального обучения программированию .NET.
A назад, я начал С#, чтобы разработать программу GUI для управления датчиками, и проект расцвел. Мне просто интересно, как лучше всего организовать код, особенно код пользовательского интерфейса, в моих формах.
Мои формы в настоящее время являются беспорядком или, по крайней мере, кажутся беспорядком для меня.
- У меня есть конструктор, который инициализирует все параметры и создает события.
- У меня есть гигантское свойство State, которое обновляет состояние Enabled во всем моем элементе управления, когда пользователи продвигаются через приложение (т.е. отключены, подключены, настроены, сканируются), управляемые перечислением состояний.
- У меня есть 3-10 частных переменных, доступных через свойства, некоторые из которых имеют побочные эффекты при изменении значений элементов формы.
- У меня есть много функций "UpdateXXX" для обработки элементов пользовательского интерфейса, которые зависят от других элементов пользовательского интерфейса - то есть: если датчик изменен, а затем измените раскрывающийся список скорости передачи. Они разделены на регионы.
- У меня есть много событий, вызывающих эти функции обновления.
- У меня есть фоновый рабочий, который выполняет все сканирование и анализ.
Моя проблема в том, что это кажется беспорядочным, особенно государственным имуществом, и становится недостижимым. Кроме того, код моей прикладной логики и код пользовательского интерфейса находятся в одном файле и в некоторой степени смешаны, что кажется неправильным и означает, что мне нужно сделать много прокрутки, чтобы найти то, что мне нужно.
Как вы структурируете свои .net-формы?
Спасибо
Ответы
Ответ 1
Существует несколько шаблонов, которые помогут вам разделить логику в приложениях, что приводит к более чистым и более удобному коду. Шаблон MVP является хорошим, с которого можно начать. Он основан на определении 3 областей ответственности: т.е. MVP M = Model, V = View, P = Presenter. Если вы знакомы с использованием интерфейсов, все будет в порядке, в противном случае это было бы хорошим местом для начала (просмотрите основные предложения OO: инкапсуляция, абстракция, полиморфизм). Основным принципом MVP является размещение логики приложения в Presenter. Ведущая беседует с представлением (вашей формой) через интерфейс, а представление обращается к ведущему (я также использую интерфейс для этого), когда пользователь взаимодействует с ним. Модель представляет собой иерархию объектов домена решения, которая внедряет логику логики и отношения сущностей.
Большинство шаблонов пользовательского интерфейса (MVP, MCV и т.д.) пытаются сделать то же самое, независимо от ваших проблем. Ниже приведен следующий пример:
//Интерфейс вида
interface IUserDetailsView
{
string Username{set;get;}
string FirstName{get;set;}
string LastName{get;set;}
UserDetailsPresenter Presenter{get;set;}
void DisplayMessage(string message);
}
//Присвоение представления
// Стандартная форма окна, в которой есть текстовые поля, метки, комбо и т.д., Которые
class UserDetailsView : Form, IUserDetails
{
public string Username{set{txtUserName.text = value;}get{return txtUserName.text;}}
public string FirstName{set{txtFirstName.text = value;}get{return txtFirstName.text;}}
public string LastName{set{txtLastName.text = value;}get{return txtLastName.text;}}
Public UserDetailsPresenter Presenter{get;set;}
public void DisplayMaessage(string message)
{
MessageBox.Show(message);
}
private void saveButton_Click(object sender, EventArgs e)
{
Presenter.SaveUserDetails();
}
}
//Презентационная логика
класс Presenter UserDetailsPresenter
{
//Constructor
public userDetailsPresenter(IUserDetailsView view)
{
//Hold a reference to the view interface and set the view presnter
_view = view;
_view.Presenter = this;
}
private IUserDetailsView _view;
DisplayUser(string userName)
{
//Get the user from some service ...
UserDetails details = service.GetUser(userName);
//Display the data vioa the interface
_view.UserName = details.UserName;
_view.FirstName = details.FirstName;
_view.LastName = details.LastName;
}
public void SaveUserDetails()
{
//Get the user dryaiols from the view (i.e. the screen
UserDetails details = new UserDetails();
details.UserName = _view.UserName;
details.FirstName = _view.FirstName;
details.LastName = _view.LastName;
//Apply some business logic here (via the model)
if(!details.IsValidUserDetails())
{
_view.DisplayMessage("Some detail outlining the issues");
return;
}
//Call out to some service to save the data
service.UpdateUser(details);
}
}
//Наконец, модель
public class UserDetails
{
public UserName {get;set;}
public FirstName{get;set;}
public LastName{get;set;}
public bool IsValidUserDetails()
{
if(LastName == "Smith")
{
//We do not allow smiths, remember what happened last time ... or whatever
return false;
}
return true;
}
}
Надеюсь, это объясняет, как разделяется ответственность. Форма не имеет никакой логики, кроме отображения/форматирования и т.д., Ее также можно вырезать для тестирования. Ведущий является посредником между представлением и моделью и делает звонки на услуги, модель внедряет вашу бизнес-логику. Как уже было сказано, в этом шаблоне есть вариации, которые могут сделать ваш код немного более тонким и гибким, но в нем изложены основные принципы. Надеюсь, это поможет.
: -)
Ответ 2
Со сложными формами я обычно разделяю код на отдельные файлы. Вы можете сделать это с помощью "частичного класса". Каждый файл исходного кода называется на основе формы. Например, MainForm.cs, MainForm.State.cs, MainForm.Update.cs, MainForm.Menu.cs и т.д. Если у меня много сложных форм, я создам подпапку для каждого. Один совет здесь - создать форму MainForm.Wip.cs. Эта форма частичного класса - это код, над которым вы сейчас работаете. Как только вы закончите с этим кодом, вы можете переименовать его или переместить код в другие файлы исходного кода.
Кроме того, я также создам пользовательские элементы управления. Это имеет преимущество повторного использования кода, и оно перемещает множество функций из формы. Ознакомьтесь с "Разработка пользовательских элементов управления Windows Forms с помощью .NET Framework" в http://msdn.microsoft.com/en-us/library/6hws6h2t.aspx.
Отъезд Никто не заботится о том, как выглядит ваш код на http://www.codinghorror.com/blog/2007/12/nobody-cares-what-your-code-looks-like.html. Что-то подумать, прежде чем "организовать".
Ответ 3
Взгляните на модель-View-Presenter patten: http://en.wikipedia.org/wiki/Model_View_Presenter
Используя этот шаблон, код ваших форм должен содержать в основном простые каскадные вызовы ведущему, которые, в свою очередь, изменят модель, каскадные события возвращаются в представление (иногда через презентатора, в зависимости от вашей реализации).
Точка: ваши формы (представление) не должны содержать информацию о состоянии; это будет в презентаторе, и ему не нужно заботиться о том, откуда он получает данные, если данные соответствуют указанному контракту. Это способствует тестированию, так как вы можете легко проверить свои состояния и данные на презентаторе и отделить представление, разрешающее PLAF, различные презентации с теми же данными и аналогичными.
Удачи:)
Ответ 4
Некоторые быстрые предложения:
Попробуйте переместить весь ваш код, отличный от него, из форм, но только если вы хотите иметь код GUI в реальной форме. Если свойство имеет побочный эффект, вероятно, оно должно быть функцией. Ваше государственное свойство должно быть почти наверняка будет методом и посмотреть, можете ли вы вывести код из него в отдельные методы, так что это всего один вызов функции для каждого состояния.
Ответ 5
Вот ссылка на шаблон архитектуры, который используется довольно часто.
http://en.wikipedia.org/wiki/Model_View_ViewModel
Я также рассмотрю некоторые другие шаблоны архитектуры и исследую больше в этом, посмотрю примерный код и т.д.
Ответ 6
Сначала вы должны проанализировать свой код, чтобы разделить логику приложения и логику пользовательского интерфейса. Оба они никогда не должны находиться в одном файле. Ваше состояние - это, безусловно, не логика UI, поэтому сначала выведите его из своей формы. Это поможет вам очистить код формы.
Во-вторых, ознакомьтесь с некоторыми шаблонами проектирования и принципами. Вы можете найти несколько отличных примеров здесь, в вашем случае я бы рассмотрел поведенческие шаблоны, точнее, шаблон State и Mediator. Они не являются серебряными пулями для решения ваших проблем, но это должно дать вам лучшее представление о том, как разделить приложение и логику пользовательского интерфейса.
Ответ 7
Я стараюсь использовать как можно больше кода в пользовательских элементах или пользовательских элементах управления. Компоненты легче использовать повторно, а код формы легче читать.
Usercontrols также может обрабатывать и выставлять события, которые могут облегчить разделение динамических частей из кода формы.
Вы даже можете создавать настраиваемые элементы управления, которые нельзя увидеть в форме, подобной таймеру.
Ответ 8
Я использую регионы, например:
#Region "_Edit"
Private Sub _edit_VisibleChanged(...) Handles _edit.VisibleChanged
End Sub
#End Region
сверху вниз, мой код формы:
- частные объявления
- свойства друга
- friend subs
- частные свойства
- частные подписчики
- события
- обработчики событий для частных форм/классов
похоже, что ваше свойство штата нужно разбить или, возможно, код переместился в другие классы или подпрограммы, чтобы сложность была более скрытой.