2

流暢なインターフェイスを使用して単純なダイアログボックス(およびその他のUI要素)を定義する経験を探しています。

(社内のプログラミング言語にカスタムダイアログボックスのサポートを追加する必要があるかもしれません。流暢なインターフェイスがそれを行うための最良の方法かもしれないと思います)

UIシステムは、回答に影響する場合はWinformsまたはWPFに基づいて構築されます。


インターフェイスが流暢でなく、質問を「ドラッグアンドドロップ」UIデザイナーの使用に依存しない「使いやすい(そして読む)API..」に変更した場合はどうなりますか。

結果はある程度流暢になると思います。

Textbox(「名前」)。Labelled(「個人名」)。列(1)

テキストボックス(「メモ」)。ラベル付き(「メモ」)。Multiline(4)。Column(1).ToColumn(3)

ただし、インターフェイスは1行である必要はありません


この「データバインディングタイプを安全にし、リファクタリングをサポートする方法」は、データバインディングの流暢なインターフェイスの良い出発点になります。

4

5 に答える 5

3

ダイアログボックス用の流暢なインターフェイスを構築しました。これは次のようなものです。

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

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

私はまた、次のような列挙型を取り込むための1つを持っていました:

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

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

列挙型からボタンを生成し、選択したボタンの列挙型の値を返しました。

編集:コメントから追加:

表示されるフォームの幅は、すべてのボタンが1行に収まるように計算されています。コントロールを追加する方法があります。レイアウトはフローレイアウトパネルから作成されます(1つはボタン用に水平、もう1つはテキストおよびその他のコントロール用に垂直)一般的なレイアウトは標準のメッセージボックスです。ボタンを自動加速するための別のオプションがあります。

メソッドの概要:

.Buttons(paramarray of DialogResult)
.FromEnum<T>(enum)
.Title(text)
.Text(text)
.Control(control)
.AutoAccelerate
.Icon(image)
.Show() as T
于 2009-08-09T13:48:13.877 に答える
2

この質問は私を数日間夢中にさせてきました。あなたが尋ねる必要があるかもしれない質問は、「なぜダイアログボックス用の流暢なAPIを作るべきなのか」ということだと思います。

人気のある流暢なAPIを見ると、ユーザーがコード行を流暢に読めるようになるという点で、それらに共通する何かに気付くでしょう。まるで文章のようです。観察:

Ninjectから:

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

Moqから:

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 = ""
};

そして、これは単なる例です。レイアウトなどをすべて1行のコードに詰め込む方法を尋ねられていることに気づきました。私の良さあなたのラインは長くなるでしょう。

流暢なAPIがここで何かを得ていると本当に思うかどうかを判断する必要があると思います。私が見るのは、ダイアログボックスにプロパティを設定し、読みやすさや値を提供しないメソッドだけです。

于 2009-08-12T03:41:06.800 に答える
2

これまでに示した例は、タスクの複雑さを軽減するために何もしていません。それらは、ある構文を別の(ほぼ同じように冗長な)構文と交換するだけです。流暢なインターフェースを作成するために時間を費やす場合は、それを活用して、構文糖衣構文を揺さぶるだけでなく、APIの表現力を実際に向上させてください。デフォルトのプリミティブ(ボタン、モダリティなど)からテンプレート、視覚的な継承チェーン、および動作への抽象化のレベルを上げます。

私はまだこれを完全には考えていませんが、次のようなものがあります。

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

また

Dialog
 .UseErrorFormatting
 .SetTitleTo("Uh Oh")
 .Show()
于 2009-08-15T10:44:19.570 に答える
1

流暢なインターフェイスの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 ();

これにより、提供された特性を持つダイアログボックスが生成されます。それはあなたが探しているものですか?

于 2009-08-09T13:44:58.730 に答える
1

私は、拡張メソッドと、匿名メソッドと組み合わせた流暢な呼び出しの単一の「コンテキスト」について優れた経験を持っています。

例がより明確になることを願っています:

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;
        }
    }
}
于 2009-08-17T09:37:20.283 に答える