Избегайте дублирования логики между WinForm и UserControl - PullRequest
0 голосов
/ 02 декабря 2009

Я нашел вопрос, который, как я полагаю, это то, что я искал, но были некоторые вещи, которые я не следовал в ответах. Поэтому я хотел бы задать вопрос по-другому (спасибо за ваше терпение). Вот ссылка, на которую я ссылаюсь:

Как избежать дублирования логики на двух похожих WinForms?

OK. У меня есть диалог, который я создал. У нас есть элементы управления для пользовательского ввода, кнопки для отображения других диалогов (для получения другого ввода) и т. Д. Эстетически, я предпочитаю диалог с элементами управления, расположенными вертикально. Во всяком случае, я также думал о создании версии этого диалога UserControl. Этот UserControl будет иметь все те же элементы управления и ту же логику, но элементы управления будут размечены совершенно по-другому (больше по горизонтали, чем по вертикали).

Итак, я не могу просто создать еще один (третий) UserControl, который я перетаскиваю в оригинальной форме и в UserControl, который я хочу создать. (Этот третий UserControl будет содержать всю логику - таким образом, разделяя между ними) Я не могу сделать это из-за разных макетов.

У меня нет проблем с созданием двух (Form, UserControl), с элементами управления, расположенными по-разному, но я не хочу «вырезать и вставить» всю логику из одного в другой.

Это не похоже на случай с MVP или MVC. Моя модель - это сам диалог. Диалог инициализируется с некоторыми значениями, да, но после инициализации «Модель» становится дополнительным пользовательским вводом (который я затем беру, когда они нажимают кнопку ОК).

Возьмем, к примеру, этот код (событие для одной из моих кнопок в этом диалоговом окне):

    private void EditQuery_Click(object sender, EventArgs e)
    {
        try
        {
            EditQueryParameters();
        }
        catch (System.Exception ex)
        {
            // TODO: Write ErrMsg to Log file.
            MessageBox.Show("Edit Query Parameters Error:\n\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

    private void EditQueryParameters()
    {
        if (m_ReportType.QueryScoreDetails && optPickDetail.Checked)
        {
            // This brings up a different type of dialog
            QueryDetails();
            return;
        }

        // DateRange, StartDate, and EndDate are all saved from the last time
        // I called this dialog
        DateType DtType = new DateType(m_ReportType.DBDateRangeField,
            m_DateRange, m_StartDate, m_EndDate);
        // StartTime, EndTime too!
        TimeType TmType = new TimeType(m_ReportType.DBTimeRangeField,
            m_StartTime, m_EndTime);

        List<AdvancedFilter> Filters = null;
        if (lstAdvancedQuery.Items.Count > 0)
        {
            Filters = new List<AdvancedFilter>();
        }
        for (int i = 0; i < lstAdvancedQuery.Items.Count; ++i)
        {
            Filters.Add((AdvancedFilter)lstAdvancedQuery.Items[i]);
        }

        // QueryType is also saved from the last time I called QueryBuilder
        QueryBuilder QryBuilder = new QueryBuilder(m_ReportType.DBCatalog, m_ReportType.DBTable,
            m_QueryType, ref DtType, ref TmType, ref Filters);

        // I am using Visual WebGUI, I have to do it this way
        QryBuilder.Closed += new EventHandler(QryBuilder_Closed);
        QryBuilder.ShowDialog();
    }

Я имею в виду, я полагаю, у меня мог бы быть некоторый "логический" класс, который выставляет что-то вроде:

    public void EditQueryParameters(ref ReportType RptType, bool PickDetail,
         string DateRange, DateTime StartDate, DateTime EndDate,
         DateTime StartTime, DateTime EndTime, string QueryType)
    {
        if (ReportType.QueryScoreDetails && PickDetail)
        {
            // This brings up a different type of dialog
            QueryDetails();
            return;
        }


        DateType DtType = new DateType(ReportType.DBDateRangeField,
            DateRange, StartDate, EndDate);
        TimeType TmType = new TimeType(ReportType.DBTimeRangeField,
            StartTime, EndTime);

        // Yikes, more stuff to add to the signature of my method
        // Will have to pull this outside the method and pass in Filters
        List<AdvancedFilter> Filters = null;
        if (lstAdvancedQuery.Items.Count > 0)
        {
            Filters = new List<AdvancedFilter>();
        }
        for (int i = 0; i < lstAdvancedQuery.Items.Count; ++i)
        {
            Filters.Add((AdvancedFilter)lstAdvancedQuery.Items[i]);
        }

        // QueryType is also saved from the last time I called QueryBuilder
        QueryBuilder QryBuilder = new QueryBuilder(ReportType.DBCatalog, ReportType.DBTable,
            QueryType, ref DtType, ref TmType, ref Filters);

        // I am using Visual WebGUI, I have to do it this way
        QryBuilder.Closed += new EventHandler(QryBuilder_Closed);
        QryBuilder.ShowDialog();
    }

Существует множество настроек для использования этого метода. Я не знаю, может быть, я ищу что-то еще .. "пятно"?

Кроме того, посмотрите на некоторые (не все) моего кода инициализации (он вызывается из constructor или form_Load; кажется, не стоит добавлять это в класс логики, так что это все еще "вырезано и вставить "между двумя):

    private void InitializeUserDefinedTitle()
    {
        txtUserTitle.Text = m_UserTitle;
    }

    private void InitializePrintSelectionCriteria()
    {
        // Print Selection Criteria
        chkSelectionCriteria.Checked = m_printSelectionCriteria;
    }

    private void InitializeTrendBy()
    {
        cmbTrend.Items.AddRange(Enum.GetNames(typeof(TrendBy)));
        cmbTrend.SelectedIndex = (int)m_TrendBy;
        cmbTrend.Visible = m_ReportType.TrendVisible;
        lblTrend.Visible = m_ReportType.TrendVisible;
    }

В итоге, исходная WinForm - это диалоговое окно, которое инициализировано данными (конструктор), отображается пользователю для ввода, когда они подтверждают диалог, в котором данные извлекаются (и эти данные хранятся вне диалогового окна, в элементе переменные, в следующий раз они вызывают диалог - это потому, что мы хотим показать, что они в последний раз выбирали / вводили).

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

Спасибо.

Ответы [ 2 ]

2 голосов
/ 02 декабря 2009

Вы можете сделать два элемента управления A и B, каждый из которых содержит одинаковые кнопки и / или другие элементы управления вводом, расположенные по-разному. Элементы управления A и B будут иметь идентичные свойства и события. Форма (или третий элемент управления) будет содержать обработчики событий, которые позволяют содержать логику только в одном месте.

Вы можете отобразить элемент управления A или B, используя свойство visible или добавив его к свойству container.controls, контейнером является содержащая форма или элемент управления.

И, например, вместо того, чтобы иметь обработчик для button1 в элементах управления A и B, который обрабатывает всю логику нажатия кнопки, обработчики для button1 в элементах управления A и B просто вызовут событие, которое будет обработано Контейнер контроля A или B.

1 голос
/ 02 декабря 2009

Вместо инкапсуляции логики я бы инкапсулировал макет. Используйте свойство пользовательского элемента управления, чтобы указать, какой макет вы хотите. Затем, где бы он ни находился (автономная форма, один из трех экземпляров в одной и той же форме), вы получаете к нему доступ и задаете макет одинаково.

Что касается , как для инкапсуляции макета, существует множество возможностей. Вы можете просто сделать это программно, то есть написать каждую версию кода макета. (Программная версия была бы более чистой, если бы вы использовали какие-то контейнеры макетов, такие как панели в WPF.) Вы можете нарисовать макет в конструкторе и скопировать сгенерированный код. Различные версии логики компоновки могут быть вставлены в приватные методы или инкапсулированы в объекты.

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