Как я могу создать свободный интерфейс для определения диалоговых окон? - PullRequest
2 голосов
/ 07 августа 2009

Я ищу примеры и опыта использования свободного интерфейса для определения простых диалоговых окон (и других элементов пользовательского интерфейса).

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

Система пользовательского интерфейса будет построена на Winforms ИЛИ WPF, если это повлияет на ваши ответы.


Что, если интерфейс не является беглым, и я изменил вопрос на «простой в использовании (и читаемый) API ...», который не зависит от использования конструктора пользовательского интерфейса «перетаскивания».

Я думаю, что результат будет в некоторой степени плавным, например,

Textbox ( «имя»). Меченый ( «Person Название"). Колонка (1)

TextBox ( «Примечание»). Меченые ( «Примечания»). Многострочный (4). Колонка (1) .ToColumn (3)

Однако интерфейс не должен быть одной строкой


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

Ответы [ 6 ]

3 голосов
/ 09 августа 2009

Я создал свободный интерфейс для своих диалоговых окон, что-то вроде:

var result = Dialog
               .Buttons(buttons.Ok, buttons.Cancel)
               .Title("")
               .Text("")
               .Show();

if ( result == DialogResult.Ok) {
    //...
}

У меня также был один для ввода в перечисление что-то вроде этого:

var result = Dialog(of EnumName)
               .Text("")
               .Title("")
               .Show();

if ( result == EnumName.Value1 ) {
  //...
}

Который сгенерировал кнопки из перечисления и возвратил выбранное значение перечисления кнопок.

Редактировать: Добавлено из комментариев:

Отображаемая форма имеет ширину, рассчитанную для размещения всех кнопок в одной строке,У него есть метод для добавления дополнительных элементов управления.Макет сделан из панелей макета потока (одна горизонтальная для кнопок. Одна вертикальная для текстовых и других элементов управления). Общий макет представляет собой стандартное окно сообщения.У него есть еще один вариант автоматического ускорения кнопок.

Сводка методов:

.Buttons(paramarray of DialogResult)
.FromEnum<T>(enum)
.Title(text)
.Text(text)
.Control(control)
.AutoAccelerate
.Icon(image)
.Show() as T
2 голосов
/ 15 августа 2009

Приведенные выше примеры ничего не делают для уменьшения сложности задачи; они обменивают только один синтаксис на другой (почти одинаково подробный). Если вы тратите время на создание свободного интерфейса, используйте его для фактического улучшения выразительности вашего API вместо того, чтобы просто манипулировать синтаксическим сахаром. Повышение уровня абстракции от стандартных примитивов (кнопок, модальностей, ...) до шаблонов, визуальных цепочек наследования и поведений.

Я еще не полностью обдумал это, но что-то вроде:

Dialog
 .WithStandardColors()
 .WithTitleOf("ChooseSomething")
 .WithButtonSet<OkCancel>()
 .Show();

или

Dialog
 .UseErrorFormatting
 .SetTitleTo("Uh Oh")
 .Show()
2 голосов
/ 12 августа 2009

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

Когда вы посмотрите на популярные свободно распространяемые API, вы заметите нечто общее с ними в том, что оно помогает пользователю свободно читать строку кода. Почти как предложение. Обратите внимание:

От Ninject:

Bind(typeof(IWeapon)).To(typeof(Sword));

От Мок:

mock.Setup(foo => foo.Execute("ping"))
    .Returns(() => calls)
    .Callback(() => calls++);

От матери всех беглых API, Linq:

var query = Products
    .Where(p => p.Name.Contains("foo")
    .OrderBy(p => p.Name);

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

В качестве другого примера, как это:

Dialog.Buttons(buttons.Ok, buttons.Cancel).Title("").Text("")

Более читабельно и полезнее, чем

new Dialog()
{
     Buttons = Buttons.OkCancel,
     Title = "",
     Text = ""
};

И это всего лишь простой пример. Я заметил, что вы спрашиваете, как собрать вещи вроде макета и т. Д. В одну строку кода. Боже мой, твои строки будут длинными.

Я думаю, вам нужно решить, действительно ли вы думаете, что свободный API приносит вам что-то здесь. Все, что я вижу, - это методы, которые устанавливают свойства в диалоговом окне и не обеспечивают читабельности или значения.

1 голос
/ 17 августа 2009

У меня хороший опыт работы с методами расширения и единым «контекстом» свободного вызова в сочетании с анонимными методами.

Надеюсь, пример будет более понятным:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TcKs.FluentSample {
    class FluentSample {
        Form CreateDialogBox() {
            var frm = new Form();
            frm.AddTextField( "Simple text field:" )
                .AddTextField( "Advanced text field:", null, txt => txt.BackColor = Color.Red )
                .AddTextField( "Complex text field:", lbl => {
                    lbl.Click += ( _sender, _e ) => MessageBox.Show( lbl, "Some informative text.", "Help" );
                    lbl.Font = new Font( lbl.Font, FontStyle.Underline );
                    lbl.Cursor = Cursors.Hand;
                },
                    txt => {
                        txt.TextChanged += ( _sender, _e ) => txt.BackColor = txt.TextLength > 0 ? SystemColors.Window : Color.Red;
                        txt.DoubleClick += ( _sender, _e ) => { /* TODO: show lookup dialog */ };
                        txt.AddErrorProvider();
                    } )
                .AddButton( btn => btn.Click += ( _sender, _e ) => frm.Close() );

            return frm;
        }
    }

    // contains standard extension methods for fluent creation of control
    static class StandardControlFluentExtensionMethods {
        // this extension method create button and add them to parent
        public static T AddButton<T>( this T parent ) where T : Control {
            return AddButton<T>( parent, (Action<Button>)null );
        }
        // this extension method create button and add them to parent, then call initMethod
        public static T AddButton<T>( this T parent, Action<Button> initButton ) where T : Control {
            var button = new Button();
            parent.Controls.Add( button );
            if ( null != initButton ) { initButton( button ); }
            return parent;
        }
    }

    // contains specialized extension methods for fluent creation of control
    static class SpecializedControlFluentExtensionMethods {
        public static T AddCloseButton<T>( this T parent, Action<Button> initButton ) where T : Control {
            return parent.AddButton( btn => {
                var frm = btn.FindForm();
                if ( null != frm ) { frm.Close(); }

                if ( null != initButton ) { initButton( btn ); }
            } );
        }
    }

    // contains data-driven extension methods for fluent creation of control
    static class DataDrivenControlFluentExtensionMethods {
        public static TParent AddTextField<TParent>( this TParent parent, string title ) where TParent : Control {
            return AddTextField<TParent>( parent, title, (Action<Label>)null, (Action<TextBox>)null );
        }
        public static TParent AddTextField<TParent>( this TParent parent, string title, Action<Label> initTitle, Action<TextBox> initEditor ) where TParent : Control {
            Label lblTitle = new Label();
            // lblTitle .....
            if ( null != initTitle ) { initTitle( lblTitle ); }

            TextBox txtEditor = new TextBox();
            // txtEditor ....
            if ( null != initEditor ) { initEditor( txtEditor ); }

            return parent;
        }

        public static TParent AddErrorProvider<TParent>( this TParent parent ) where TParent : Control {
            return AddErrorProvider( parent, (Action<ErrorProvider>)null );
        }
        public static TParent AddErrorProvider<TParent>( this TParent parent, Action<ErrorProvider> initErrorProvider ) where TParent : Control {
            // create and/or initilaize error provider
            return parent;
        }
    }
}
1 голос
/ 09 августа 2009

LINQ пример свободного интерфейса:

var customerTurnover = allOrders
                       .Where (o.CustomerID == CustomerID)
                       .Sum (o => o.Amount);

По сути, это способ разработки интерфейсов для сведения к минимуму многословия и обеспечения естественного и удобочитаемого способа объединения операций для достижения многого с небольшим кодом.

Мнимый пример для домена диалоговых окон:

DialogBoxAPI
.ModalDialogBox ()
.RoundCornersStyle ()
.BackgroundColor (RGB (200, 200, 200))
.TextColor (0, 0, 0)
.MessageText ("What shall we decide?")
.OKButton ()
.CancelButton ();

, который будет генерировать диалоговое окно с предоставленными характеристиками. Это то, что вы ищете?

0 голосов
/ 12 августа 2009

Это был очень интересный вопрос. Я прочитал статью в Википедии об этом, и у нее был превосходный пример.

http://en.wikipedia.org/wiki/Fluent_interface

...