Fluent API Support

  • 4 minutes to read

Fluent APIs utilize method cascading to relay the instruction context of a subsequent call. By doing so, a Fluent API follows the same natural language rules as those utilized by people. As a result, a well-constructed Fluent API provides more human-friendly code that is easier to perceive and understand.

NOTE

To get started with Fluent API concepts, refer to the following articles.

  • A Look at Fluent APIs

    A Code Project blog post by Sacha Barber that describes what Fluent API is and why you should use it.

  • Code First Fluent API

    The MSDN documentation section that describes Fluent API in the scope of the Entity Framework.

The DevExpress MVVM Framework provides extension methods to build Fluent API expressions for any task: from binding simple properties to relating MVVM behaviors with specific events.

Property Binding and UI Triggers

Related article: Data Bindings and Notifications

  • Simple property binding.

    
    mvvmContext.ViewModelType = typeof(ViewModel);
    var fluentAPI = mvvmContext.OfType<ViewModel>();
    fluentAPI.SetBinding(editor, e => e.EditValue, x => x.Title);
    //ViewModel
    public virtual string Title { get; set; }
    
  • Binding to nested properties.

    
    mvvmContext.ViewModelType = typeof(ViewModel);
    var fluent = mvvmContext.OfType<ViewModel>();
    fluent.SetBinding(editor, e => e.EditValue, x => x.Child.Title);
    //ViewModel
    public NestedViewModel Child { get; private set; }
    //NestedViewModel
    public virtual string Title { get; set; }
    
  • UI Triggers.

    
    mvvmContext.ViewModelType = typeof(UIViewModel);
    var fluentAPI = mvvmContext.OfType<UIViewModel>();
    fluentAPI.SetTrigger(x => x.IsActive, (active) =>
    {
        label.Text = active ? "Active" : "Inactive";
    });
    //UIViewModel
    public virtual bool IsActive { get; set; }
    

Command Binding

Related article: Commands

  • Parameterized commands with CanExecute conditions.

    
    mvvmContext.ViewModelType = typeof(ViewModel);
    int parameter = 4;
    var fluentAPI = mvvmContext.OfType<ViewModel>();
    fluentAPI.BindCommand(commandButton, (x, p) => x.DoSomething(p), x => parameter);
    
    //ViewModel
    public class ViewModel {
        public void DoSomething(int p) {
            //. . .
        }
    
        public bool CanDoSomething(int p) {
            return (2 + 2) == p;
        }
    }
    
  • Asynchronous commands.

    
    mvvmContext.ViewModelType = typeof(ViewModel);
    var fluentAPI = mvvmContext.OfType<ViewModel>();
    fluentAPI.BindCommand(commandButton, x => x.DoSomethingAsynchronously());
    fluentAPI.BindCancelCommand(cancelButton, x => x.DoSomethingAsynchronously());
    
    //ViewModel
    public class ViewModelWithAsyncCommandAndCancellation 
        public Task DoSomethingAsynchronously() {
            return Task.Factory.StartNew(() =>
            {
                var asyncCommand = this.GetAsyncCommand(x => x.DoSomethingAsynchronously());
                for(int i = 0; i <= 100; i++) {
                    if(asyncCommand.IsCancellationRequested) // cancellation check
                        break;
                    //. . .
                }
            });
        }
    }
    
  • The WithCommand extension allows you to bind a command to one or multiple target UI elements.

    
    //binding to one UI element
    fluent.WithCommand(x => x.DoSomething())
           .Bind(btnDoSomething);
    //binding to multiple UI elements
    fluent.WithCommand(x => x.DoSomething())
           .Bind(btn1DoSomething)
           .Bind(btn2DoSomething);
    fluent.WithCommand(x => x.DoSomethingAsynchronously())
           .Bind(btnDo)
           .BindCancel(btnCancel);
    
  • Command triggers allow you to automatically call specific methods before the target command is executed, after that, or when this command's CanExecute condition changes.

    
    fluent.WithCommand(x => x.DoSomething())
           .After(() => AfterDoSomethingExecuted());
    fluent.WithCommand(x => x.DoSomething())
           .Before(() => BeforeDoSomethingExecuted());
    fluent.WithCommand(x => x.DoSomething())
           .OnCanExecuteChanged(() => WhenCanDoSomethingChanged());
    

Attaching Behaviors

Related article: Behaviors

  • Confirmation behavior.

    
    mvvmContext.WithEvent<ChangingEventArgs>(editor, "EditValueChanging")
        .Confirmation(behavior =>
        {
            behavior.Caption = "CheckEdit State changing";
            behavior.Text = "This checkEdit's checked-state is about to be changed. Are you sure?";
        });
    
  • Event-To-Command Behaviors

    
    mvvmContext.ViewModelType = typeof(ViewModel);
    mvvmContext.WithEvent<ViewModel, EventArgs>(thirdPartyButton, "Click")
        .EventToCommand(x => x.DoSomething());
    
    //ViewModel
    public void DoSomething() {
        //. . .
    }
    
  • Key-To-Command and Keys-To-Command Behaviors

    
    mvvmContext.OfType<KeyAwareViewModel>()
            .WithKey(memo, Keys.A)
            .KeyToCommand(x => x.OnAKey());
    mvvmContext.OfType<KeyAwareViewModel>()
            .WithKeys(memo, new Keys[] { Keys.A, Keys.B, Keys.C })
            .KeysToCommand(x => x.OnKey(Keys.None), args => args.KeyCode);