现在的位置: 首页 > 综合 > 正文

monocross 几个重要的基类

2013年10月05日 ⁄ 综合 ⁄ 共 15795字 ⁄ 字号 评论关闭
文章目录

主要说说MonoCross中重要的几个基类和接口,主要是摘抄,给自己忘记的时候看看,因为几个类很重要,所以我觉得很有必要摘抄

书上是以一个demo展开讲这几个基类的,所以我也按照这个顺序来写,思路才不会奇奇怪怪的。

Using MVC pattern

Model

像前面的文章说到的,build一个monocross应用,第一步是先定义好Model,下面是一个customer managment system的Customer的Model定义

public class Customer
{
  public Customer()
  {
    ID = “0”;
    Name = string.Empty;
    Website = string.Empty;
    PrimaryAddress = new Address();
    Addresses = new List<Address>();
    Contacts = new List<Contact>();
    Orders = new List<Order>();
  }
  public string ID { get; set; }
  public string Name { get; set; }
  public string Website { get; set; }
  public string PrimaryPhone { get; set; }
  public Address PrimaryAddress { get; set; }
  public List<Address> Addresses { get; set; }
  public List<Contact> Contacts { get; set; }
  public List<Order> Orders { get; set; }
} 

Controller

Now that you’ve defi ned your model object, you need to create a controller that can load the model from your system-of-record and make any business decisions about processing of the model for presentation in your views. Controllers in a MonoCross application
are inherited from the abstract MXController<T> class.

建好Model之后,就要建Controller了,所有Monocross中的Controller都是继承于抽象类MXController<T>的

using System;
using System.Collections.Generic;
namespace MonoCross.Navigation
{
  public interface IMXController{
    Dictionary<string, string> Parameters { get; set; }
    String Uri { get; set; }
    IMXView View { get; set; }
    Type ModelType { get; }
    object GetModel();
    string Load(Dictionary<string, string> parameters);
    void RenderView();
  }
  public abstract class MXController<T> : IMXController
  {
    public string Uri { get; set; }
    public Dictionary<string, string> Parameters { get; set; }
    public T Model { get; set; }
    public Type ModelType { get { return typeof(T); } }
    public virtual IMXView View { get; set; }
    public object GetModel() { return Model; }
    public abstract string Load(Dictionary<string, string> parameters);
    public virtual void RenderView() { if (View != null) View.Render(); }
    }
}

上面是接口IMXController和抽象类MXController<T>的定义。

下面是Customer类的Controller实现的一部分代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml.Serialization;
using MonoCross.Navigation;
using CustomerManagement.Shared;
using CustomerManagement.Shared.Model;
namespace CustomerManagement.Controllers
{
  public class CustomerController : MXController<Customer>
  {
    public override string Load(Dictionary<string, string> parameters)
    {
      string perspective = ViewPerspective.Default;
      string customerId = null;
      parameters.TryGetValue(“CustomerId”, out customerId);
                    
      // get the action, assumes 
      string action;
      if (!parameters.TryGetValue(“Action”, out action))  {
        // set default action if none specified
        action = “GET”;
        }
    switch (action)
      {
        case “EDIT”:
        case “GET”:
        // populate the customer model
        if (customerId == null)
          throw new Exception(“No Customer Id found”);
          if (string.Equals(customerId.ToUpper(), “NEW”)) {
            // assign Model a new customer for editing 
            Model = new Customer();
            perspective = ViewPerspective.Update;
          } else {
            Model = GetCustomer(customerId);
            if (String.Equals(action, “EDIT”))
              perspective = ViewPerspective.Update;
            else
              perspective = ViewPerspective.Default;
            }
          break;
        case “DELETE”:
          if (customerId == null)
            customerId = Model.ID;
            // post delete request to the server
            DeleteCustomer(customerId);
            // return and let redirected controller execute, 
          // remaining navigation is ignored
          MXContainer.Instance.Redirect(“Customers”);
          return ViewPerspective.Delete;
      case “CREATE”:
        // process addition of new model
        if(AddNewCustomer(Model))
          MXContainer.Instance.Redirect(“Customers”);
        break;
      case “UPDATE”:
        if(UpdateCustomer(Model))
          MXContainer.Instance.Redirect(“Customers”);
        break;
    }
    return perspective;
  }

The  Load() method of the  CustomerController  is where you write any logic necessary to initialize and prepare your Company object for presentation. The  Load() method receives a dictionary of parameters on the argument that contains any model-specifi
c information passed in the navigation call that loads the controller. In this case, you pass the unique “Customer” identifi er for the company you want to load, make a call to the data service to retrieve the company data, and then set the model property
of the CustomerController  to a new  Company object instance.

View

As mentioned previously in this chapter, the MonoCross pattern implements a Separated Interface pattern to provide a loose-coupling of the presentation layer to the shared application code. This separation is accomplished through the IMXView interface.
public interface IMXView
{
  Type ModelType { get; }
  void SetModel(object model);
  void Render();
}

The  IMXView interface defi nes the implementation contract for all MonoCross views. The interface consists of the properties, methods, and events necessary  for the MonoCross navigation framework to initialize the rendering of a view from
a controller in the shared application. This approach offers great fl exibility in defi  ning views across multiple mobile platforms. You can implement your views using whatever approach is required by the target platform, provided you implement the IMXView
interface.

render方法就是在这里定义的
下面是MXView的定义,其中实现了接口IMXView
using System;
namespace MonoCross.Navigation
{
  public delegate void ModelEventHandler(object model);
  public interface IMXView
  {
    Type ModelType { get; }
    void SetModel(object model);
    void Render();
  }
  public abstract class MXView<T> : IMXView
  {    
    public Type ModelType { get { return typeof(T); } }
    public virtual void SetModel(object model)
    {
      Model = (T)model;
    }
    public virtual void Render() { }
    public virtual T Model { get; set; }
  }
}

Use the MXView<T> class to create a view for your Customer model class. For simplicity in illustrating the concept, the view in Listing 4-6 has been created for the Windows Console target.
下面是控制台实现Customer view的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MonoCross.Navigation;
using MonoCross.Console;
using CustomerManagement.Shared.Model;
namespace CustomerManagement.Console.Views
{
  class CustomerView : MXConsoleView<Customer>
  {
    public override void Render()
    {
      System.Console.Clear();
      System.Console.WriteLine(“Customer Details”);
      System.Console.WriteLine();
      System.Console.WriteLine(Model.Name);
      System.Console
        .WriteLine(string
          .Format(“{0} {1}”, 
            Model.PrimaryAddress.Street1, 
            Model.PrimaryAddress.Street2));
      System.Console
        .WriteLine(string
          .Format(“{0}, {1}  {2}”, 
            Model.PrimaryAddress.City, 
            Model.PrimaryAddress.State, 
            Model.PrimaryAddress.Zip)); 
      System.Console
        .WriteLine(“Previous Orders: “ + Model.Orders.Count.ToString());
      System.Console
        .WriteLine(“Addresses:” + Model.Addresses.Count.ToString()); 
      System.Console
        .WriteLine(“Contacts: “ + Model.Contacts.Count.ToString());
      System.Console.WriteLine();
      System.Console.WriteLine(“Web: “ + Model.Website);
      System.Console.WriteLine(“Phone: “ + Model.PrimaryPhone);
      System.Console.WriteLine();
      System.Console.WriteLine(“Enter to Continue, (D)elete or (E)dit”);
      while (true)
      {
        string input = System.Console.ReadLine().Trim();
        if (input.Length == 0)
        {
          this.Back();
          return;
        }
        else if (input.StartsWith(“E”))
        {
          this.Navigate(“Customers/” + Model.ID + “/EDIT”);
        }
        else if (input.StartsWith(“D”))
        {
          this.Navigate(“Customers/” + Model.ID + “/DELETE”);
        }
      }
    }
  }
}

The  Render()  method of the  CustomerView class is where you define the logic to display your model customer instance to the user. In this case the model property values are simply displayed in the appropriate format using the  Console.WriteLine()
method. 
看完上面几个基类后,下面需要看看将他们联系起来的几个类以及方法

Using URI-Based Navigation

To turn your MVC combinations into a cohesive application, you need a mechanism to bind them together. The MonoCross navigation framework provides that 
mechanism using a URI-based navigation structure. Each controller in your application is associ-ated with one or more URI endpoints that uniquely identify its place or places in the application workflow. Each action in your application, whether selecting an
item from a list or saving a form, is represented as a navigation to one of these controller endpoints. By using this technique, MonoCross enables the defi nition of any number of complex workfl  ows, while at the same time encapsulating 
and reusing as much controller business logic as possible. MonoCross navigation also builds upon the loosely coupled MVC pattern described previously with the addition of two important concepts: a shared application and a platform container.

Building the Shared Application

The shared application in MonoCross encapsulates your MVC modules into a logical, cohesive structure. All the business and data access logic for your application will be shared across mobile platform targets, so the basic workfl ow navigation is defi ned
in this same structure. 
MXApplication定义了一个shared application所需要的方法和属性
using System;
using System.Collections.Generic;
using System.Linq;
namespace MonoCross.Navigation
{
  public abstract class MXApplication
  {
    public string NavigateOnLoad { get; set; }
    public string Title { get; set; }
    public NavigationList NavigationMap = new NavigationList();
    protected MXApplication()
    {
      NavigateOnLoad = string.Empty;
      OnAppLoad();
    }
    public virtual void OnAppLoad() { }
    public virtual void OnAppLoadComplete() { }
    public class NavigationList : List<MXNavigation>
    {
      public void Add(string pattern, IMXController controller)
      {
        this.Add(pattern, controller, new Dictionary<string, string>());
      }
      public IMXController GetControllerForPattern(string pattern)
      {
        return this.Contains(pattern) 
          ? this.Where(m => m.Pattern == pattern)
            .First().Controller 
          : null;
      }
     public String GetPatternForModelType(Type modelType)
      {
        return this.Where(m => m.Controller.ModelType == modelType)
          .First().Pattern;
      }
      public bool Contains(string pattern)
      {
        return this.Where(m => m.Pattern == pattern).Count() > 0;
      }
      public void Add(string pattern, 
                      IMXController controller, 
                      Dictionary<string, string> parameters)
      {
#if DROID
        Android.Util.Log.Debug(“NavigationList”, “Adding: ‘” + pattern + “’”);
#endif
        // Enforce uniqueness
        MXNavigation currentMatch = this
          .Where(m => m.Pattern == pattern)
          .FirstOrDefault();
        if (currentMatch != null)
        {
#if DEBUG
          string text = string
           .Format(“MapUri \”{0}\” is already matched to Controller type {1}”,
                   pattern, currentMatch.Controller);
          throw new Exception(text);
#else
          return;
#endif
        }
        this.Add(new MXNavigation(pattern, controller, parameters));
      }
    }
  }
}

You inherit from the MXApplication  class to create your MonoCross application and register your workflow endpoints for navigation. 

下面是继续是customer management的例子
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MonoCross.Navigation;
using CustomerManagement.Controllers;
namespace CustomerManagement
{
  public class App : MXApplication
  {
    public override void OnAppLoad()
    {
      // Set the application title
      Title = “Customer Management”;
      // Add navigation mappings
      NavigationMap.Add(“Customers”, new CustomerListController());
      CustomerController customerController = new CustomerController();
      NavigationMap.Add(“Customers/{CustomerId}”, customerController);
      NavigationMap.Add(“Customers/{CustomerId}/{Action}”, customerController);
      // Set default navigation URI
      NavigateOnLoad = “Customers”;
    }
  }
} 

Adding Controllers to the Navigation Map

The MonoCross navigation framework is based on RESTful routing principles. Each unique point in your application workflow is defined by a parameterized URI endpoint that corresponds to a controller associated with one or more views used for presentation
of the model. Navigation endpoints are registered in the  NavigationMap  found in the  MXApplication  class.
这里说的是 每个controller之间的切换都是通过在这里定义切换时候所传参数,切换到哪个controller都是以URI的方式来定义的,并且存于NavigationMap这个链表中。
CustomerController customerController = new CustomerController();
NavigationMap.Add(“Customers/{CustomerId}”, customerController);
This establishes the default entry point for an individual order. The URI template shown uses the squiggly bracket syntax ( { } ) to indicate a substituted value, (in this case  “CustomerId”) in the navigation URI. So a URI of  Customers/1234 loads the  CustomerController
 from your NavigationMap . At runtime, the navigation framework extracts the individual customer identifier, and places it in the controller parameters argument passed to the  CustomerController.Load() method as a name/value pair, (CustomerId=1234).
所以controller中的paramaters属性有哪些参数就是在这里定义的。
在Customer management的navigationMap中,有这么一句 

NavigationMap.Add(“Customers/{CustomerId}/{Action}”, customerController);

是在customController中选择一个Action操作后,再次去到另一个customController中,看会前面的customer的controller就可以看到在load方法中,有取了action参数出来,然后根据参数不同的取值,进行不同的操作。这样就把一个controller多次使用了。

Adding a Platform Container

The abstract  MXContainer class provides a default implementation of a platform container. Each supported platform in MonoCross has a concrete implementation that inherits from the MXContainer class and provides platform-specifi c helper methods and utilities.
For the Windows Console example in this chapter, use the ConsoleContainer class to initialize your application and  register your views
MXConsoleContainer定义
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using MonoCross.Navigation;
namespace MonoCross.Console
{
  public static class MXConsoleNavigationExtensions
  {
    public static void Back(this IMXView view)
    {
      MXConsoleContainer.Back(view);
    }
  }
  public class MXConsoleContainer : MXContainer
  {
    public MXConsoleContainer(MXApplication theApp)
      : base(theApp)
    { }
    private class NavDetail
    {
      public string Path { get; set; }
      public Dictionary<string, string> Parameters { get; set; }
      public NavDetail(string path, Dictionary<string, string> parameters)
      {
        Path = path;
        Parameters = parameters;
      }
    }
    static Stack<NavDetail> NavHistory = new Stack<NavDetail>();
        
    public static void Initialize(MXApplication theApp)
    {
      MXContainer.InitializeContainer(new MXConsoleContainer(theApp));
      // non-threaded container, not needed as all input is blocking (old-school)
      MXContainer.Instance.ThreadedLoad = false;
    }
    public static void Back(IMXView view)
    {
      // exit if we try to go back too far
      if (!CanGoBack())
      {
        Environment.Exit(0);
      }
      else
      {
        // pop off the current view
        NavHistory.Pop();                
        // prepare to re-push the current view
        NavDetail backTo = NavHistory.Pop();
        // re-display the view
        Navigate(view, backTo.Path, backTo.Parameters);
      }
    }
    public static bool CanGoBack()
    {
      if (NavHistory.Count > 1)
        return true;
      else
        return false;
    }
    protected override void OnControllerLoadComplete(
        IMXView fromView, 
        IMXController controller, 
        MXViewPerspective perspective)
    {
      // store of the stack for later
      NavHistory.Push(new NavDetail(controller.Uri, controller.Parameters));
      // render the view
      MXConsoleContainer.RenderViewFromPerspective(controller, perspective);
    }
    protected override void OnControllerLoadFailed(IMXController controller, 
        Exception ex)
    {
      System.Console.WriteLine(“Failed to load controller: “ + ex.Message);
      System.Console.WriteLine(“Stack Dump”);
      System.Console.WriteLine(ex.StackTrace.ToString());
      System.Diagnostics.Debug.WriteLine(“Failed to load controller: “ 
                                         + ex.Message);
      System.Diagnostics.Debug.WriteLine(“Stack Dump”);
      System.Diagnostics.Debug.WriteLine(ex.StackTrace.ToString());
    }
    public override void Redirect(string url)
    {
      Navigate(null, url);
      CancelLoad = true;
    }
  }    
} 

next shows the code for initializing your container. You need to start by providing it an instance of your shared app. You also register the views for your application by calling the AddView() method on the container and passing a new instance of each view
to be placed in the view map. In this case, you register two views: The first displays a list of customers in the system and the second displays the details of a single customer, which is an instance of the CustomerView class discussed earlier in this chapter. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MonoCross.Navigation;
using MonoCross.Console;
using CustomerManagement;
using CustomerManagement.Controllers;
using CustomerManagement.Shared;
using CustomerManagement.Shared.Model;
namespace CustomerManagement.Console
{
  class Program
  {
    static void Main(string[] args)
    {
      // initialize container
      MXConsoleContainer.Initialize(new CustomerManagement.App());
      // customer list view
      MXConsoleContainer.AddView<List<Customer>>(new Views.CustomerListView(),
                                                 ViewPerspective.Default);
      // customer view and customer edit/new
      MXConsoleContainer.AddView<Customer>(new Views.CustomerView(),
                                           ViewPerspective.Default);
      MXConsoleContainer.AddView<Customer>(new Views.CustomerEdit(),
                                           ViewPerspective.Update);
      // navigate to first view
      MXConsoleContainer.Navigate(MXContainer.Instance.App.NavigateOnLoad);
    }
  }
} 

一个controller会对应一个view 所以这里初始化view的数目要和navigationMap中德controller的一样,而且名字最好对应上,增加可读性。注意到AddView函数里面的第二个参数是ViewPerspective的,下面就说说这个参数

Working with View Perspectives

A view perspective is simply a string that describes the intended purpose of your view. 

public static class ViewPerspective
{
  public const string Default = “”;
  public const string Read = “GET”;
  public const string Create = “POST”;
  public const string Update = “PUT”;
  public const string Delete = “DELETE”;
}

View perspectives are used to uniquely register views in your container and are also used by your controllers to indicate to the container which view to render at a given point in your application. 

The view perspective concept is designed for maximum fl exibility. You can register your views with whatever string value adequately describes the intended function. When you want to display that view from your controller, simply return the corresponding
view perspective value to your container, and the desired view renders.
大概就这些了 把MonoCross的流程又走了一遍 把几个基类看了下 还是挺重要的 这几天一直往后看了 现在回过头来看这些 收获不少。

抱歉!评论已关闭.