2009-08-07 55 views
2

我在尋找的例子使用流利的界面來定義簡單的對話框(和其他UI元素)的經驗如何創建一個流暢的界面來定義對話框?

(我可能需要爲自定義對話框支持添加到一個內部的編程語言,我認爲一個流暢的界面可能是做的最好的方式)將被建立在的WinForms

UI系統OR WPF如果影響你的答案。如果


界面不流暢,我改變只是一個「簡單的使用(讀)API。」不依賴於使用的「拖放」的問題UI設計師。

我想結果會流利的在一定程度上,e.g

文本框(「名」)。標記(「人 名稱」)。列(1)

文本框(「註釋」)。標記(「注意事項」)。 多行(4)。柱(1).ToColumn(3)

但是該接口不必須是一個單個線


這種「How to make Databinding type safe and support refactoring」 給出了用於綁定流暢界面的良好起點。一個連貫接口的

+0

可以提供流暢的界面的樣本? – 2009-08-09 12:35:51

+0

rAyt,我試圖發現的一部分是流暢接口的用法應該看起來像 – 2009-08-09 12:52:02

+0

爲什麼不告訴我們「對話框」到底是什麼意思?你需要一個消息框,一個表單或其他東西嗎? – 2009-08-12 07:58:42

回答

2

迄今給出的例子並沒有減少任務的複雜性;他們只交易另一種語法(幾乎同樣冗長)。如果你花時間來創建一個流暢的界面,利用它來實際上改善你的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 2009-08-09 13:57:58

+0

@Dykam:這是一個選項,是的。由作者決定他喜歡哪種風格 - 有幾個選項作爲方法參數或幾個不帶參數的獨立方法。 – 2009-08-09 13:59:49

+0

是的。如果存在多個選項,api會變得混亂,則可能會出現問題。 – Dykam 2009-08-09 14:13:11

3

我建了一個流暢的界面,我的對話框,沿着線的東西:

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 
+0

它的工作效果如何,您遇到了哪些問題? – 2009-08-09 13:50:49

+0

我幾乎沒有使用第一個例子,但我一直使用第二個例子。我幾乎從不需要再創建一個特殊的對話框,只需定義一個枚舉(或使用現有的對象)並使用該對話框即可。它唯一的缺點是,如果你通過一個巨大的枚舉,超過大約4件物品,但你可以添加範圍過濾作爲戰鬥的選擇。 – Pondidum 2009-08-09 15:05:36

+1

這個例子表明,在我看來,有一些流暢的界面不好。至少把它們改爲介詞,比如「.WithTitle(」和「.ContainingText」(如果你覺得你必須沿着一堆屬性設置進行字符串間的轉換)。 – 2009-08-09 15:15:23

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

更有用,這只是一個簡單的例子。我注意到你正在問如何在一行代碼中填充佈局等東西。我的天啊,你的路線會很長。

我認爲你需要決定,如果你真的想能說一口流利的API在這裏獲得你什麼。我看到的所有方法都是在對話框中設置屬性,並且不提供任何可讀性或值。

+0

+1,因爲沒有流暢的API收益。 – bernhof 2009-08-20 08:04:16

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; 
     } 
    } 
} 
相關問題