2

I found some similar questions and I like the solution with the "MultipleButtonAttribute" found at here: How do you handle multiple submit buttons in ASP.NET MVC Framework?
But I come up with another solution and I thought I share it with the community.

Community
  • 1
  • 1
Péter
  • 2,161
  • 3
  • 21
  • 30

1 Answers1

2

So first of all I make a ModelBinder that handle the incoming request.
I have to made a restriction. input/button element id and name must be a prefix of "cmd".

  public class CommandModelBinder<T> : IModelBinder
  {
    public CommandModelBinder()
    {
      if (!typeof(T).IsEnum)
      {
        throw new ArgumentException("T must be an enumerated type");
      }
    }

    public object BindModel(System.Web.Mvc.ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
      string commandText = controllerContext.HttpContext.Request.Form.AllKeys.Single(key => key.StartsWith("cmd"));
      return Enum.Parse(typeof (T), commandText.Substring(3));
    }
  }

Of course it can be changed or make it to configurable via web.config of App_Start.
The next thing I make is a HtmlHelper extension to generate the necessary HTML markup:

public static MvcHtmlString CommandButton<T>(this HtmlHelper helper, string text, T command)
{
  if (!command.GetType().IsEnum) throw new ArgumentException("T must be an enumerated type");
  string identifier = "cmd" + command;
  TagBuilder tagBuilder = new TagBuilder("input");
  tagBuilder.Attributes["id"] = identifier;
  tagBuilder.Attributes["name"] = identifier;
  tagBuilder.Attributes["value"] = text;
  tagBuilder.Attributes["type"] = "submit";
  return new MvcHtmlString(tagBuilder.ToString());
}

It's still a tech demo so the html attribute and the other super overloads waiting for you to develop on your own.
Now we have to make some enumerations to try our code. They can be general or controller specific:

  public enum IndexCommands
  {
    Save,
    Cancel
  }

  public enum YesNo
  {
    Yes,
    No
  }  

Now pair the enumerations with the binders. I do it in different file in the App_Start folder. ModelBinderConfig.

  ModelBinders.Binders.Add(typeof(IndexCommands), new CommandModelBinder<IndexCommands>());
  ModelBinders.Binders.Add(typeof(YesNo), new CommandModelBinder<YesNo>());

Now after we set up everything, make an action to try the codes. I kept it simple so:

public ActionResult Index()
{
  return View();
}

[HttpPost]
public ActionResult Index(IndexCommands command)
{
  return View();
}

And my view looks like this:

@using (Html.BeginForm())
{
  @Html.CommandButton("Save", IndexCommands.Save)
  @Html.CommandButton("Cancel", IndexCommands.Cancel)
}

Hope this helps to keep your code clear, type safe and readable.

Péter
  • 2,161
  • 3
  • 21
  • 30