【问题标题】:Generically Render Partial View - Convert PropertyInfo into Concrete Object通用渲染局部视图 - 将 PropertyInfo 转换为具体对象
【发布时间】:2018-10-10 10:21:27
【问题描述】:

我目前正在 MVC (c#) 中制作向导。但是我的向导视图中有一个 if 语句,如下所示:

if (Model.Wizard.ClientDetails.GetStep() == Model.Wizard.CurrentStep)
{
    @Html.PartialFor(x => x.Wizard.ClientDetails, "_Step");
}
else if (Model.Wizard.Preferences.GetStep() == Model.Wizard.CurrentStep)
{
    @Html.PartialFor(x => x.Wizard.ClientPreferences, "_Step")
}
else if (Model.Wizard.ClientQuestions.GetStep() == Model.Wizard.CurrentStep)
{
    @Html.PartialFor(x => x.Wizard.ClientQuestions, "_Step")
}

除了我选择显示哪个部分的视图的这一部分之外,向导的设置非常通用。从上面的代码可以看出,每个if 都遵循相同的结构。唯一改变的部分是Model.Wizard.**Property** 部分。

我想尝试删除此 if 语句,这样我就不必担心为添加到新向导的每个步骤编写 if 语句。

我想把代码改成这样:

@Html.PartialFor(x => x.ExampleWizardTransaction.GetStepObject(), "_Step");

我目前对GetStepObject方法的尝试如下:

public static T GetStepObject<T>(this IWizardTransaction wizardTransaction) 
     where T : class, new()
{
    var properties = wizardTransaction.GetType().GetProperties()
            .Where(x => x.PropertyType.GetCustomAttributes(typeof(StepAttribute), true).Any());

    PropertyInfo @object = properties.FirstOrDefault(x => ((StepAttribute)Attribute
            .GetCustomAttribute(x.PropertyType, typeof(StepAttribute))).Step == wizardTransaction.CurrentStep);

}

PropertyInfo @object 部件正在正确选择向导中当前步骤的属性信息。我需要能够将 PropertyInfo @object PropertyInfo 作为正确类型及其当前值返回并以某种方式返回。

这可能吗?

编辑#1:

现有的PartialFor 在正常情况下工作。

public static MvcHtmlString PartialFor<TModel, TProperty>(
    this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
    var name = ExpressionHelper.GetExpressionText(expression);
    var model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
    var viewData = new ViewDataDictionary(helper.ViewData)
    {
        TemplateInfo = new TemplateInfo { HtmlFieldPrefix = name }
    };
    return helper.Partial(partialViewName, model, viewData);
}

编辑#2:

值未绑定的原因是var name = ExpressionHelper.GetExpressionText(expression); 部分返回一个空白字符串。如果我将name 变量硬编码为实际属性,则绑定有效。例如:

public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper,
    Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
    var compiled = expression.Compile();
    var result = compiled.Invoke(helper.ViewData.Model);

    var name = ExpressionHelper.GetExpressionText(expression); 
    //Should be ExampleWizardTransaction.ClientDetails for this step but is blank

    var viewData = new ViewDataDictionary(helper.ViewData)
    {
        TemplateInfo = new TemplateInfo 
        { 
             //HtmlFieldPrefix = name
             HtmlFieldPrefix = "ExampleWizardTransaction.ClientDetails" 
        }
        //Hard coded this to ExampleWizardTransaction.ClientDetails and the bindings now work
    };

    return helper.Partial(partialViewName, result, viewData);
 }

看来我需要能够将向导对象的名称和当前步骤对象作为字符串值传递给TemplateInfo

【问题讨论】:

  • 您能否提供更多关于您的课程结构的信息?在不知道课程结构的情况下询问有关课程反射的问题有点困难。

标签: c# asp.net-mvc generics asp.net-mvc-partialview


【解决方案1】:

我要对你的班级结构进行疯狂的猜测。假设您的课程是这样的:

[AttributeUsage(AttributeTargets.Property, AllowMultiple =false)]
public class StepAttribute: Attribute
{
    public StepEnum Step { get; set; }
}

public interface IWizardStep
{

}

public interface IWizardTransaction
{

}

public enum StepEnum
{
    Previous,
    CurrentStep
}

public class WizardStep: IWizardStep
{
    public string StepName { get; set; }

    public override string ToString()
    {
        return StepName;
    }
}

public class Wizard : IWizardTransaction
{
    [Step(Step = StepEnum.Previous)]
    public WizardStep ClientDetails => new WizardStep() { StepName = "ClientDetails" };
    [Step(Step = StepEnum.CurrentStep)]
    public WizardStep ClientQuestions => new WizardStep() { StepName = "ClientQuestions" };
}

假设也实现了 PartialFor 方法

    public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> html, 
            Expression<Func<TModel, TProperty>> expression, string partialViewName)
    {
        var compiled = expression.Compile();
        var result = compiled.Invoke(html.ViewData.Model);
        return html.Partial(partialViewName, result);
    }

那么GetStepObject的这个实现就可以工作了

    public static TProperty GetStepObject<TProperty>(this IWizardTransaction wizardTransaction)
        where TProperty : class
    {
        var properties = wizardTransaction.GetType().GetProperties()
                .Where(x => x.GetCustomAttributes(typeof(StepAttribute), true).Any());
        PropertyInfo @object = properties.FirstOrDefault(x => 
                    (x.GetCustomAttributes(typeof(StepAttribute), true).SingleOrDefault()
                                as StepAttribute).Step == StepEnum.CurrentStep);
        return @object.GetValue(wizardTransaction) as TProperty;
    }

有了这个名为 _Step.cshtml 的局部视图的实现,像这样

@model PartialView.Models.WizardStep

@Model

你的视图可以这样称呼它

@model PartialView.Models.Wizard
@using PartialView.Models;
@{
    ViewBag.Title = "Partial view calling";
}

@Html.PartialFor(m=>m.GetStepObject<WizardStep>(), "_Step")

视觉结果将是一个带有 html 文本 ClientQuestions

的空白页面

【讨论】:

  • 嗨,Alfredo,我已更新我的答案以包含用于现有 PartialFor 方法的代码。您提供的代码确实允许构建解决方案并加载页面,但似乎绑定值丢失或未绑定。
  • 嗨,Alfredo,我再次更新了答案,导致绑定丢失。
  • 我想出了一个变通办法让绑定正常工作,所以感谢您为我指明正确的方向!
猜你喜欢
  • 1970-01-01
  • 2013-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-17
  • 2023-03-30
  • 2013-01-13
相关资源
最近更新 更多