支持MVC ViewUserControl中的ViewState

时间:2011-09-15 18:35:44

标签: c# asp.net-mvc asp.net-mvc-3

我知道我知道,这与谷物有关。在每个人都想要讲述MVC模式之前,这是一个极端的措施。我有一个ASP.NET控件,我必须在MVC中工作,需要ViewState,并希望重点留在此。我知道我可以load a classic ASP.NET pages in MVC by a trick of routes,但我需要一个适合MVC框架的完整解决方案。

必须有一种方法可以扩展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永远不会。

3 个答案:

答案 0 :(得分:0)

你正试图将方形钉固定在一个圆孔中,但是......

要使ViewState工作,整个组合页面(内容+主控+控件)要求您有<form runat="server">包装所有需要ViewState的元素。在WebForms中,您只能在页面中拥有其中一个。您的控件应该位于具有该表单元素的同一页面中。如果你把它放在使用RenderPartial等调用的东西中,那么它可能无法工作。如果您将它放在正确的位置,您可能必须确保调用额外的页面事件以保持/加载视图状态。甚至一旦你确保控件的服务器端点击事件正常工作可能会更加困难。

我知道您不想听,但从长远来看,最好使用WebForms页面或重写内容以使用专为Mvc设计的组件。

答案 1 :(得分:0)

Telerik在MVC框架中支持他们的RadControls;我用过其中的一些。您可以在此处找到博客文章: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。

答案 2 :(得分: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;
        }
    }
}