2011-09-15 47 views
0

我知道我知道,它違背了穀物。在每個人都想講述MVC模式之前,這是一個極端的措施。我有一個ASP.NET控件,我必須在MVC中工作,這需要ViewState,並且非常感謝關注這一點。我知道我可以load a classic ASP.NET pages in MVC by a trick of routes,但我需要一個適合MVC框架的整體解決方案。在MVC中支持ViewState ViewUserControl

必須有一種方法來擴展ViewUserControl以與ViewState遊戲,過濾器或屬性一起玩,甚至通過解析請求來模擬ViewState對象,並以某種方式在管道的早期重寫某些內容以調用LoadViewState 。

唉,恐怕我對經典ASP.NET不夠熟悉,不知道該怎麼做。 ViewUserControl具有從UserControl對象派生的ViewState屬性以及SaveViewState和LoadViewState方法,所以我看到了一些希望。

這是我到目前爲止有:

<%@ Control Language="C#" CodeBehind="RadGridExample.ascx.cs" Inherits="MvcApplication5.Views.Shared.RadGridExample" %> 
<form runat="server"> 

    <telerik:RadScriptManager ID="scriptmanager2" runat="server"></telerik:RadScriptManager> 

    <telerik:RadGrid runat="server" ID="RadGrid1" AutoGenerateColumns="false" AllowMultiRowSelection="true" ShowGroupPanel="true"> 
     <MasterTableView TableLayout="Fixed" > 
      <Columns> 
       <telerik:GridBoundColumn DataField="Name" HeaderText="Name" DataType="System.String" /> 
       <telerik:GridBoundColumn DataField="Age" HeaderText="Age" DataType="System.String" /> 
      </Columns> 
     </MasterTableView> 
     <ClientSettings AllowDragToGroup="true" > 
     </ClientSettings> 
    </telerik:RadGrid> 

</form> 

的局部視圖背後的代碼:

namespace MvcApplication5.Views.Shared 
{ 
    public class RadGridExample : ViewUserControl 
    { 
     protected void Page_Init() 
     { 
      HomeIndexViewModel viewModel = this.Model as HomeIndexViewModel; 

      RadGrid grid = this.Controls[0].FindControl("RadGrid1") as RadGrid; 

      grid.DataSource = viewModel.Animals; 

      grid.DataBind(); 
     } 

     protected override void LoadViewState(object savedState) 
     { 
      base.LoadViewState(savedState); 
     } 

     protected override object SaveViewState() 
     { 
      return base.SaveViewState(); 
     } 
    } 
} 

有趣的事情,在SaveViewState被調用,但LoadViewState從來不會。

+0

所以我假設,因爲你可以在MVC項目中有一個web表單頁面,你不能恢復到web表單這一個控制的方法?此外,這是一個ASP.NET自定義控件,它是你自己還是第三方供應商? –

+0

嘿@布萊恩,是的沒有。對這一個控件使用經典的asp.net模式(如下所述:http://weblogs.asp.net/rajbk/archive/2010/05/11/running-asp-net-webforms-and-asp-net-mvc -side-by-side.aspx)是我的最後一招。問題是它是一個廣泛的MVC應用程序的一部分,具有安全屬性和模型吊銷。這將導致大量的改造,以獲得與安全性和傳入模型相當的asp.net頁面。儘管我們可以擴展MVC,但我拒絕相信從填充的Request中篡改ViewState並獲得MVC與它一起玩是不可能的。 – Levitikon

+0

這是一個三十方控制,Telerik的RadGrid。我可以訪問源代碼,並且一直追溯到簡單的實現Control的LoadViewState從未被調用的步驟。 – Levitikon

回答

0

所有進入這裏的人都不要放棄希望。我能夠找到解決方案,雖然它不是很漂亮。它使用一點反射和硬編碼映射到對象樹。希望這對於任何需要MVC中的ViewState的人來說都是一個很好的起點。

管窺:

<%@ Control Language="C#" CodeBehind="RadGridExample.ascx.cs" Inherits="MvcApplication5.Views.Shared.RadGridExample" %> 
<form runat="server"> 

    <telerik:RadScriptManager ID="scriptmanager2" runat="server"></telerik:RadScriptManager> 

    <telerik:RadGrid runat="server" ID="RadGrid1" AutoGenerateColumns="false" AllowMultiRowSelection="true" ShowGroupPanel="true" AllowFilteringByColumn="True" > 
     <MasterTableView TableLayout="Fixed" > 
      <Columns> 
       <telerik:GridBoundColumn DataField="Name" HeaderText="Name" DataType="System.String" /> 
       <telerik:GridBoundColumn DataField="Age" HeaderText="Age" DataType="System.String" /> 
      </Columns> 
     </MasterTableView> 
     <ClientSettings AllowDragToGroup="true" AllowGroupExpandCollapse="false" > 
     </ClientSettings> 
    </telerik:RadGrid> 

</form> 

後面的代碼:

using System.Reflection; 
using System.Web.Mvc; 
using System.Web.UI; 
using MvcApplication5.Models.ViewModels; 
using Telerik.Web.UI; 

namespace MvcApplication5.Views.Shared 
{ 
    public class RadGridExample : ViewUserControl 
    { 
     protected void Page_Init() 
     { 
      RadGrid grid = this.Controls[0].FindControl("RadGrid1") as RadGrid; 

      grid.NeedDataSource += new GridNeedDataSourceEventHandler(grid_NeedDataSource); 

      grid.DataBind(); 

      string viewState = Request.Form["__VIEWSTATE"]; 

      if (!string.IsNullOrEmpty(viewState)) 
      { 
       LosFormatter formatter = new LosFormatter(); 

       object savedStateObject = formatter.Deserialize(viewState); 

       MethodInfo method = grid.GetType().GetMethod("LoadViewState", BindingFlags.NonPublic | BindingFlags.Instance); 

       // TODO: Find a less brittle/more elegant way to isolate the appropiate viewstate object for this control 
       // In the case of Telerik's RadGrid, the key wasy find the tree that had an array of 13 objects 
       method.Invoke(grid, new object[] { (((((((((savedStateObject as Pair).First as Pair).Second as Pair).Second as System.Collections.ArrayList)[1] as Pair).Second as System.Collections.ArrayList)[1] as Pair).Second as System.Collections.ArrayList)[1] as Pair).First }); 
      } 

      string eventArgument = Request.Form["__EVENTARGUMENT"]; 

      if (!string.IsNullOrEmpty(eventArgument)) 
      { 
       grid.RaisePostBackEvent(eventArgument); 
      } 
     } 

     void grid_NeedDataSource(object sender, GridNeedDataSourceEventArgs e) 
     { 
      (sender as RadGrid).DataSource = this.Model as HomeIndexViewModel; 
     } 
    } 
} 
0

您正在試圖將方釘成圓形孔,但是....

要獲得ViewState的工作你的整個組成頁面(內容+主控+控制),需要你有一個包裹<form runat="server">所有需要ViewState的元素。而在WebForms中,你只能在頁面中找到其中的一個。您的控件應該位於具有該表單元素的同一頁面中。如果你把它放在使用RenderPartial等被調用的東西中,那麼它可能不起作用。如果你在正確的位置,你可能需要確保額外的頁面事件被調用來保持/加載視圖狀態。即使一旦你做到了這一點,確保控件的服務器端點擊事件正常工作可能會更困難。

我知道你不想聽到它,但從長遠來看,最好使用WebForms頁面或重寫某些東西以使用爲Mvc設計的組件。

+0

哈哈,這更像是試圖讓一頭大象坐在圓洞裏。這很痛苦!感謝信息順便說一句。我已經儘可能的使用Runat服務器形式的ViewState隱藏參數來呈現控件了。由於ViewState在MVC生命週期中沒有被加載,所以在回發時發生了stinker(有趣的是使用了MVC的postback)。你會如何推薦調用ViewState的持久性? – Levitikon

0

Telerik在MVC框架中支持他們的RadControl;我使用了其中的一些。你可以在這裏找到一篇博客文章:http://blogs.telerik.com/aspnetmvcteam/posts/08-11-06/asp_net_ajax_controls_in_asp_net_mvc.aspx

自從他們發佈MVC開源框架以來,我還沒有做過。但是,他們已經發布了一組幫助器擴展,以便在MVC中使用它們的控件,該控件應該在某處可用。

所以這應該不成問題。他們還使用MVC中的ASP.NET AJAX控件進行了示例演示,可在此處獲得:http://www.telerikwatch.com/2009/01/telerik-mvc-demo-app-now-available.html

HTH。