如何使用MVC中的存储库模式创建动态的多个部分视图

时间:2013-04-25 17:38:46

标签: asp.net-mvc-3 model-view-controller model partial-views renderpartial

我正在尝试使用一般主页,根据传递给控件的参数,将显示不同的内容(模块)。

例如,用户可以从菜单中选择肯塔基州,肯塔基州的ID是1.家庭控制器获取id(1)并确定可能的模块 state(一个简单的db调用。)也许有一个公告模块和一个状态的联系人模块。公告模块可能有几个项目,但它只有一个模块。每种类型的模块都会有部分视图。

这是我的基本设置。

public interface IModuleRepository
{
    IList<MenuItemModule> GetMenuItemModules(int menuItem);
    IList<Announcements> GetAnnouncements(int modID);
    IList<News> GetNews(int modID);
    IList<Contacts> GetContacts(int modID);
}



//business object
public class MenuItemModule
{

    private int _MenuItemID;
    private int _ModuleID;
    private int _ModuleDefID;
    private string _Src;
    private int _ModuleOrder;

//get, set properties for these...

}

//announcements entity
public class Announcements
{
    private int _ID = -1;
    private int _MenuItemID = -1;
    private int _ModuleID = -1;
    private string _Description = string.Empty;

//get set props ...
}

在我的家庭控制器中......

public class HomeController : Controller
{


    private IModuleRepository modRepository;

    public HomeController(IModuleRepository modRepository)
    {
        this.modRepository = modRepository;
    }


    public ViewResult Item(string ItemID)
    {

        //returns a list of menuitemmodules for the page.  This gives me the Src or name of each
        //module on the page, i.e. Announcements, news, contacts, etc. 
        var modules = modRepository.GetMenuItemModules(Convert.ToInt32(ItemID)); 


        return View(modules);

   }

}

我已经尝试了几种不同的模型,但我总是遇到一些限制。如果我将menuitemmodules传递给我的Item.aspx,那么我可以这样做:

   foreach (var mod in Model)           
   {               
        Html.RenderPartial(mod.Src, a);      //needs an announcement object though    
   } 

这使它有点动态,因为我有Src基本上就像“公告”,我可以创建一个announcements.ascx部分来处理模块。但我发现很难通过我的menuitemmodule和公告实体。

我还搞乱了传递一个更复杂的对象,然后使用If语句测试每个Src。随着我增加应用程序中可能的模块数量,这将使未来的扩展变得困难。

如何解决我的问题?我希望我提供了足够的信息。我喜欢这里的基本想法 - http://www.mikesdotnetting.com/Article/105/ASP.NET-MVC-Partial-Views-and-Strongly-Typed-Custom-ViewModels,但这似乎只适用于页面上的静态模块。

我尝试了一个名为ModuleViewModel的复合视图模型。这是尝试:

public class ModuleViewModel
{
    public IList<Announcements> announcements { get; set; }
    public IList<MenuItemModule> mods { get; set; }

}

如果我将该模型传递给Item.aspx,我可以做这样的事情(但我必须做错事,因为看起来不对劲。)

   foreach (var mod in Model)           
   {

       if (mod.announcements.Count > 0)
       {
           Html.RenderPartial("Announcements", mod.announcements);
       }


   } 

再次,可扩展性将困扰我。我希望在项目页面上有类似的内容:

   foreach (var mod in Model)           
   {

           Html.RenderPartial(mod.Src, mod);          

   } 

这将是正确的局部视图并将其传递给正确的模型。

2 个答案:

答案 0 :(得分:0)

创建派生自公共模块基类的模块类:

public class AnnouncementsModule : Module
{
}

public class ContactsModule : Module
{
}

在控制器中:

创建各种模块并将它们放入整个视图模块(这里有一个名为Modules的属性,它是Module的数组:

var viewModel = new ComplexViewModel 
                { 
                    Modules = new [] 
                    { 
                       new ContactsModule(), 
                       new AnnouncementsModule() 
                    }
                 };
return View(viewModule);

在视图中:

@Html.DisplayFor(x => x.Modules);

在相应的“Shared”文件夹中为每个Type模块创建部分视图。 (在没有创建它们的情况下运行它,它会向你显示一个异常,其中包含它正在寻找它们的位置)。

答案 1 :(得分:0)

经过一周多的讨论之后,我终于弄明白了MVC如何动态地做我想做的事情。我决定将其解决方案发布给MVC新手。希望以下内容能够消除我的误解(尽管在我对MVC的理解中,我不能说这是最好的方法。)

为了清晰起见,我将包含之前的代码剪辑和修改:

 public interface IModuleRepository
 {
      IList<MenuItemModule> GetMenuItemModules(int menuItem);
      IList<Announcements> GetAnnouncements(int modID);
      IList<News> GetNews(int modID);
      IList<Contacts> GetContacts(int modID);
 }



//business object
public class MenuItemModule
{

    private int _MenuItemID;
    private int _ModuleID;
    private int _ModuleDefID;
    private string _Src;
    private int _ModuleOrder;

//get, set properties for these...

}

//announcements entity
public class Announcements  : MenuItemModule
{
    private int _ID = -1;
    private string _Description = string.Empty;

//get set props ...
}

我还添加了另一个类:

public class AnnouncementModule : MenuItemModule
{
    private IList<Announcements> _Announcements;
    //get set prop
}

...我为视图创建了一个模型

public class HomeItemViewModel
{
    public MenuItemModule[] MenuItemModules { get; set; } //collection of menuitemmodules
}

在我的家庭控制器中......

    var menuItemModules = modRepository.GetMenuItemModules(ItemID);

    if (menuItemModules.Count > 0)
    {
        AnnouncementModule aMod;
        MenuItemModule[] mods = new MenuItemModule[menuItemModules.Count()];

        int i = 0;

        //loop through each MenuItemModule assign to the appropriate model
        foreach (MenuItemModule mod in menuItemModules)
        {
            if (mod.Src == "Announcements")
            {
                aMod = new AnnouncementModule();
                aMod.Announcements = modRepository.GetAnnouncements(mod.ModuleID);

                //now add this to the menuitemmodule collection
                mods[i] = aMod;
            }

            if (mod.Src == "Contacts")
            {
                //...
            }

            i++;
        }

    }


    var viewModel = new HomeItemViewModel
    {
        MenuItemModules = mods
    };

    return View(viewModel);

然后我使用了建议在视图中使用DisplayFor。该视图强类型为HomeItemViewModel。

<%: Html.DisplayFor(m => m.MenuItemModules) %>

这将遍历集合,并根据类型调用该模板。在这个例子中,它调用了AnnouncementModule.ascx,它强烈地键入了AnnouncementModule。

foreach (var a in Model.Announcements)
{
    //a.Description will give us the description of the announcement
}

我意识到有更简单的方法来编码控制器,我计划重构,但这个骨架应该提供解决我发布的问题的基础知识。