nfplee
nfplee

Reputation: 7977

Editor Templates at Runtime

This problem is a little hard to explain so I'll try to give an example. Say I have the following type:

public class FieldResult<T> {
    public Field Field { get; set; }
    public T Answer { get; set; }

    public FieldResult(Field field) {
        Field = field;
    }
}

Now say I have the following view model:

public class Form {
    public IList<FieldResult<object>> Results { get; set; }

    public Form(IList<Field> fields) {
        Results = fields.Select(f => new FieldResult<object>(f)).ToList();
    }
}

If I say the following in the view:

@foreach (var result in Model.Results) {
    @Html.EditorFor(m => result, "CheckBoxField")
}

Now say I have the following CheckBoxField editor template:

@model FieldResult<bool>
@Html.CheckBoxFor(m => m.Answer)

It all compiles fine but I get the following error at runtime:

The model item passed into the dictionary is of type 'FieldResult1[System.Object]', but this dictionary requires a model item of type 'FieldResult1[System.Boolean]'.

I'd appreciate it if someone could say whether this is possible and possibly suggest a way of going about it. Thanks

Upvotes: 0

Views: 266

Answers (1)

R&#233;da Mattar
R&#233;da Mattar

Reputation: 4381

You try to pass a FieldResult<object> value in a template whose model is of type FieldResult<bool>, they're different types so you get that error. You can either change your Results property and make it an IList<FieldResult<bool>>, or cast your collection items in your view.

If you need to build different types of results, you can also consider using class inheritance :

public abstract class FieldResult {
    public Field Field { get; set; }

    public FieldResult(Field field) {
        Field = field;
    }
}

public class BooleanFieldResult : FieldResult {
    public bool Answer { get; set; }

    public FieldResult(Field field) : base(field) {
    }
}

Your Form class would look like this :

public class Form {
    public IList<FieldResult> Results { get; set; }

    public Form(IList<Field> fields) {
        Results = // ... you choose which child class inherited from FieldResult you want to use
    }
}

Your view would check which type it is :

@foreach (var result in Model.Results) {
    if(result is BooleanFieldResult) {
        var booleanResult = (BooleanFieldResult)result;
        @Html.EditorFor(m => booleanResult , "CheckBoxField")
    }
}

Then your CheckBoxField template would look like this :

@model BooleanFieldResult
@Html.CheckBoxFor(m => m.Answer)

Upvotes: 1

Related Questions