2009-08-07 7 views
2

私はの例をで、流暢なインターフェイスを使って簡単なダイアログボックス(および他のUI要素)を定義することを探しています。ダイアログボックスを定義するための流暢なインターフェイスを作成するにはどうすればよいですか?

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

UIシステムORそれがあなたの答えに影響を及ぼす場合WPF。


インタフェースが流暢ではないと私はちょうどへの質問変えたらどう「を使用(読み)するシンプルなAPIを..」「ドラッグ&ドロップ」UIの使用に依存しません。デザイナー。

私は結果がいくつかは、例えば

テキストボックス(「名前」)、拡張に流暢になると思います。ラベル(「Person 名前」)。列(1)

テキストボックス( "ノート")。ラベル( "Notes")。 複数行(4)。コラム(1).ToColumn(3)

インタフェースは


単一の行である必要はありません。しかし、この「How to make Databinding type safe and support refactoring」 は、データバインディングのための流れるようなインターフェイスのための良い出発点を与えます。流れるようなインターフェイスの

+0

あなたは流れるようなインターフェイスのサンプルを提供することができますか? –

+0

rAyt、私が見つけようとしているのは、流暢なインターフェイスの使い方です。 –

+0

"ダイアログボックス"とはどういう意味ですか?メッセージボックス、フォームなどが必要ですか? –

答えて

2

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

私は完全にまだを介してこれを考えていないが、の線に沿って何か:

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

または

Dialog 
.UseErrorFormatting 
.SetTitleTo("Uh Oh") 
.Show() 
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(); 

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

+0

私はお勧めします。CornerStyle(CornerStyles.Round) – Dykam

+0

@Dykam:これはオプションです。彼が好むスタイルを決定するのは作者次第です。メソッドのパラメータとしていくつかのオプションを使用したり、パラメータを持たないいくつかの個別のメソッドを使用したりします。 –

+0

真。あなたのアプローチの問題は、複数のオプションがある場合、apiが混乱することがあります。 – Dykam

3

私は、の線に沿って何か私のダイアログボックスの流れるようなインターフェイスを構築しました:生成

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

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

:私も列挙でこのような何かを取るための1つを持っていた

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

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

を列挙からボタンを選択し、選択されたボタン列挙値を返しました。

編集:コメントの追加:

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

方法の概要:

.Buttons(paramarray of DialogResult) 
.FromEnum<T>(enum) 
.Title(text) 
.Text(text) 
.Control(control) 
.AutoAccelerate 
.Icon(image) 
.Show() as T 
+0

どのくらいうまくいきましたか? –

+0

最初の例はほとんど使用しませんが、2番目の例は常に使用しています。私は、特別なダイアログボックスをこれ以上作成する必要はほとんどありません。ちょうどenumを定義するか(または既存のものを使用して)ダイアログを使用してください。その唯一の没落は、それが約4項目以上の巨大な列挙型を渡す場合ですが、戦闘のオプションとして範囲フィルタリングを追加することができます。 – Pondidum

+1

このサンプルは、流暢なインターフェースがうまくいかないことがあると私の意見で示しています。少なくとも、 ".WithTitle("と ".ContainingText(")のような前置詞に変更してください。間にドットを含むプロパティ設定の束に沿って文字列を入力する必要がある場合は –

2

この質問は数日のために狂気私を運転されています。私は質問する必要があるかもしれない質問は、 "私はダイアログボックスのための流暢な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 = "" 
}; 

よりも読みやすく、より便利で、これは単純な例です。私はあなたがレイアウトのようなものをすべて1行のコードで埋める方法を尋ねていることに気づいた。私の良さはあなたのラインが長くなるだろう。

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

+0

+1を流暢なAPIから無制限に自動追加する機能もあります。同意します。 – bernhof

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; 
     } 
    } 
} 
関連する問題