2009-08-07 19 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; 
     } 
    } 
} 
相关问题