Общее представление частичного представления - преобразование PropertyInfo в конкретный объект - PullRequest
0 голосов
/ 10 октября 2018

В настоящее время я делаю мастера в 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);
}

EDIT # 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.

1 Ответ

0 голосов
/ 10 октября 2018

Я сделаю дикую догадку о ваших классовых структурах.Предполагая, что ваши классы выглядят примерно так:

[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

...