Организация кода пользовательского интерфейса в формах .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
  • частные свойства
  • частные подписчики
  • события
  • обработчики событий для частных форм/классов

похоже, что ваше свойство штата нужно разбить или, возможно, код переместился в другие классы или подпрограммы, чтобы сложность была более скрытой.