6

我见过很多关于这个的问题,但我从来没有真正得到我需要的答案。

我正在将一个相当大的 Web 应用程序从 Web 窗体转换为 MVC,过了一会儿我遇到了将数据传递到视图的问题。在我执行代码的操作中:

//This is just an example ViewData["QProducts"] = from p in db.Products select new{Name = p.Name, Date = p.ToShortDateString() } ViewData["QUsers"] = from u in db.Users select u;

我使用 foreach 循环遍历 html 中的对象,如下所示:

foreach(var q in (IEnumerable)ViewData["QEvents"])
{ 
    /*Print the data here*/
}

在使用 MVC 之前我只使用了一个asp:Repeater,但由于这是 MVC 我不能使用 ASP.NET 控件。

我应该如何将这些数据传递给视图?我真的没有选择不在这里使用匿名类型。<%#ViewData.Eval()%>显然行不通。

有任何想法吗?

4

6 回答 6

15

创建一个类型来保存名称和日期,而不是匿名类型:

public class NameDate
{
  public string Name { get; set; }
  public DateTime Date { get; set; }
}

然后在您的 Linq 查询中使用它:

from p in db.Products select new NameDate { Name = p.Name, Date = p.Date }

强烈键入您的视图MyView<IEnumerable<NameDate>>,然后执行foreach ( var nameDate in ViewData.Model )...

于 2009-01-04T00:52:59.133 回答
2

如果你觉得有点懒,你可以在这里使用这段代码......它有点长,但基本上它是反射的包装......

var something = { Name = "Jim", Age = 25 };
AnonymousType type = AnonymousType.Create(something);

//then used...
string name = type.Get<string>("Name");
int age = type.Get<int>("Age", -1 /* optional default value */);

这是代码...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Code {

    /// <summary>
    /// A convenient method of accessing the values of an 
    /// anonymous type without needing to define a separate class
    /// </summary>
    public class AnonymousType {

        #region Constants

        private const string EXCEPTION_MISSING_PARAMETER_INFORMATION = 
            "Unable to match the parameter '{0}' to a property in the AnonymousType. This could be due to a casting problem or a Property that does not exist.";
        private const string EXCEPTION_COULD_NOT_ACCESS_FIELD =
            "Unable to find a field named '{0}' (of type {1})";
        private const string EXCEPTION_COULD_NOT_ACCESS_FIELD_AT_INDEX =
            "Unable to find a field named '{0}' at the requested index (of type {1})";

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new AutoType for methods that return Anonymus types
        /// </summary>
        public AnonymousType(object type) {
            this._Init(type, false);
        }

        /// <summary>
        /// Creates a new AutoType for methods that return Anonymus types and
        /// detetrmins if exceptions should be thrown if a type is missing
        /// </summary>
        public AnonymousType(object type, bool supressErrors) {
            this._Init(type, supressErrors);
        }

        /// <summary>
        /// Initalizes the data for the is type
        /// </summary>
        private void _Init(object type, bool supressErrors) {
            this.SupressExceptions = supressErrors;
            this.m_Type = type.GetType();
            this.m_TypeData = type; 
        }

        #endregion

        #region Static Routines

        /// <summary>
        /// Creates a new Anonymous Type from the provided object data
        /// </summary>
        public static AnonymousType Create(object data) {
            return new AnonymousType(data);
        }

        /// <summary>
        /// Creates a new Anonymous Type from the provided object data
        /// </summary>
        public static AnonymousType Create(object data, bool supressErrors) {
            return new AnonymousType(data, supressErrors);
        }

        #endregion

        #region Private Members

        /// <summary>
        /// The type that will be accessed via reflection
        /// </summary>
        private Type m_Type;

        /// <summary>
        /// The actual typs that is being used
        /// </summary>
        private object m_TypeData;

        #endregion

        #region Properties

        /// <summary>
        /// Determines if errors should be thrown if any casting errors take place
        /// </summary>
        public bool SupressExceptions { get; set; }


        /// <summary>
        /// Accessess a property by name and returns an object
        /// </summary>
        public object this[string property] {
            get {
                return this.Get<object>(property);
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Checks if this Anonymous Type has the specified property
        /// </summary>
        public bool Has(string property) {
            return ((m_Type.GetProperty(property) as PropertyInfo) != null);
        }

        /// <summary>
        /// Returns if this Anonymous type has the specified property and that
        /// the value matches the type specified
        /// </summary>
        public bool Has(string property, Type isType) {

            //try and get the property
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;

            //If this type doesn't exist at all, just return false
            if (prop == null) { return false; }

            //if it does exist, verify the type
            if (prop.PropertyType.Equals(isType)) { return true; }
            return false;

        }

        /// <summary>
        /// Returns a type value using the specified type
        /// </summary>
        public T Get<T>(string property) {

            //return this value if needed            
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
            try {
                return (T)prop.GetValue(this.m_TypeData, null);
            }
            catch (Exception ex) {
                if (this.SupressExceptions) { return default(T); }
                throw new Exception(
                    string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD, property, typeof(T).Name),
                    ex
                    );
            }
        }



        /// <summary>
        /// Returns a type value using the specified type
        /// </summary>
        public T Get<T>(string property, object[] index) {

            //return this value if needed
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
            try {
                return (T)prop.GetValue(this.m_TypeData, index);
            }
            catch (Exception ex) {
                if (this.SupressExceptions) { return default(T); }
                throw new Exception(
                    string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD_AT_INDEX, property, typeof(T).Name),
                    ex
                    );
            }
        }



        /// <summary>
        /// Returns a type value using the specified type but includes a default value
        /// if one it missing
        /// </summary>
        public T Get<T>(string property, T defaultValue) {
            //return this value if needed
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
            if (prop == null) { return defaultValue; }
            try {
                return (T)prop.GetValue(this.m_TypeData, null);
            }
            catch (Exception ex) {
                if (this.SupressExceptions) { return defaultValue; }
                throw new Exception(
                    string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD, prop, typeof(T).Name),
                    ex
                    );
            }

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1>(Action<T1> with) {

            //set a default for each of the params
            T1 param1 = default(T1);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1);

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1, T2>(Action<T1, T2> with) {

            //set a default for each of the params
            T1 param1 = default(T1);
            T2 param2 = default(T2);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;

                        case 2:
                            param2 = this.Get<T2>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1, param2);

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1, T2, T3>(Action<T1, T2, T3> with) {

            //set a default for each of the params
            T1 param1 = default(T1);
            T2 param2 = default(T2);
            T3 param3 = default(T3);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;

                        case 2:
                            param2 = this.Get<T2>(paramName);
                            break;

                        case 3:
                            param3 = this.Get<T3>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1, param2, param3);

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1, T2, T3, T4>(Action<T1, T2, T3, T4> with) {

            //set a default for each of the params
            T1 param1 = default(T1);
            T2 param2 = default(T2);
            T3 param3 = default(T3);
            T4 param4 = default(T4);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;

                        case 2:
                            param2 = this.Get<T2>(paramName);
                            break;

                        case 3:
                            param3 = this.Get<T3>(paramName);
                            break;

                        case 4:
                            param4 = this.Get<T4>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1, param2, param3, param4);

        }

        #endregion

        #region Working With Arrays

        /// <summary>
        /// Returns the specified property as an array of AnonymousTypes
        /// </summary>
        public AnonymousType[] AsArray(string property) {
            object[] values = this.Get<object[]>(property);
            return values.Select(o => {
                if (o is AnonymousType) { return (AnonymousType)o; }
                return new AnonymousType(o);
            }).ToArray();
        }

        /// <summary>
        /// Performs the specified action on each value in an array of AnonymousTypes
        /// </summary>
        public void WithEach(string property, Action<AnonymousType> action) {
            foreach (AnonymousType value in this.AsArray(property)) {
                action(value);
            }
        }

        #endregion

        #region Static Methods

        /// <summary>
        /// Returns the type of data for the provided object
        /// </summary>
        public static T Get<T>(object data, string property) {
            return new AnonymousType(data).Get<T>(property);
        }

        /// <summary>
        /// Returns the type of data for the provided object
        /// </summary>
        public static T Get<T>(object data, string property, T defaultValue) {
            return new AnonymousType(data).Get<T>(property, defaultValue);
        }

        /// <summary>
        /// Returns the type of data for the provided object
        /// </summary>
        public static AnonymousType[] AsArray(object data, string property) {
            return new AnonymousType(data).AsArray(property);
        }

        /// <summary>
        /// Performs the following action on each of the values in the specified
        /// property value for a user
        /// </summary>
        public static void WithEach(object data, string property, Action<AnonymousType> action) {
            new AnonymousType(data).WithEach(property, action);
        }

        #endregion

    }
}
于 2009-04-27T21:50:16.767 回答
1

考虑显式转换为列表并转换 ViewData:

ViewData["QUsers"] = (from u in db.Users select u).ToList();

foreach(Users u in (List<Users>)ViewData["QUsers"]){ 

    /*Print the data here*/

}

您可以通过几种方式传递数据,使用上面的 ViewData 或 TempData 在 Action 之间传递。您还可以使用 ViewData.Model 来包含强类型模型。请注意,您必须将视图的定义更改为类似

ViewPage<User>

至于一个不错的中继器替换尝试http://www.codeplex.com/MVCContrib。他们有一个 Grid Html Helper 可能会有所帮助。

于 2009-01-04T00:14:53.720 回答
1

如果你想避免创建一个单独的类来显示你的一个投影,你也可以求助于使用字典,如下所示:

from person in personList select new Dictionary<string, string>
{ 
    { "Name", person.Firstname + " " + person.Lastname },
    { "Id", person.Id.ToString() }
};

然后,您可以输入您的 viewpage 到

ViewPage<IEnumerable<Dictionary<string, string>>>

最后迭代视图中的列表,如下所示:

<% foreach (Dictionary<string, string> p in (IEnumerable)ViewData.Model) 
{ %>
   <li> <%=p["Id"] %> - <%= p["Name"] %> </li>
<% } %>

不用说,缺点是您的代码现在充满了“魔术字符串”,由于缺少编译时检查,因此更容易出错。

于 2009-04-27T21:34:51.080 回答
0

你不能只使用 MVC 中的 RouteValueDictionary 吗?

于 2010-10-27T13:17:55.373 回答
0

我怀疑您正在寻找的是 ViewModel:http: //msdn.microsoft.com/en-us/vs2010trainingcourse_aspnetmvc3fundamentals_topic7.aspx

于 2012-11-20T07:52:30.373 回答