开发者

ASP.NET MVC2 Strongly-typed view databinding question

开发者 https://www.devze.com 2023-01-21 04:37 出处:网络
I\'ll start off by saying my terminology might be off, which is why I might be having trouble finding an answer to this question, and apologising for the wall of text.

I'll start off by saying my terminology might be off, which is why I might be having trouble finding an answer to this question, and apologising for the wall of text.

I have a strongly-typed view that inherits from a custom type called Record. Record has a dictionary of named fields of varying datatypes - some strings, some ints, some DateTime/TimeSpans.

Via a dropdownlist onchange on a form, I get to a HttpPost Action method in my controller - as I understand it, the model of the current view is supposed to be 'passed through' to the controller method. It appears to be doing this, but only partially: the DateTime and TimeSpan fields of the Record are coming through as their default values. All the string, int etc fields are coming through fine.

I debugged through the Record code during the databinding that happens in the back end as the HttpPost controller method is called and it seems that a new, blank Record is constructed, then various properties are set - but if as part of constructing a 'blank' record a property is initialised to some valid, non-null value, the Set methods of those properties are never called.

My question is - what's actually happening in this databinding phase? Is it as I described it? Do I have to make all properties of my Record initialise as nulls to get them to databind properly?

Edit: The Record (simplified)

public class Record
{
    public Record() : base()
    {
        fields.Add("Id", new FieldValue { DataType = typeof(int) });     
        fields.Add("StartDateTime", new FieldValue { DataType = typeof(DateTime) });      
    }

    private Dictionary<string, FieldValue> fields = new Dictionary<string, FieldValue>();

    public Dictionary<string, FieldValue> Fields
    {
        get
        {
            return fields;
        }
    }

    public long? Id
    {
        get
        {
            FieldValue fieldValue 开发者_Go百科= Fields["Id"];
            return fieldValue != null ? (long?)fieldValue.Value : null;
        }
        set 
        {
            SetFieldValue("Id", value);
        }
    }

    public DateTime StartDateTime
    {
        get
        {
            FieldValue fieldValue = Fields["StartDateTime"];
            if (fieldValue == null || fieldValue.Value == null)
            {
                return DateTime.MinValue;
            }
            else
            {
                return (DateTime)fieldValue.Value;
            }

        }
        set
        {
            SetFieldValue("StartDateTime", value);
        }
    }

    protected void SetFieldValue(string fieldName, object value)
    {
        Fields[fieldName] = new FieldValue(value);
    }
}

The value class for the dictionary of FieldValues:

public class FieldValue
{
    internal FieldValue(object value)
    {
        DataType = value.GetType();
        Value = value;
    }

    internal FieldValue()
    { }

    public Type DataType { get; set; }  //The data type of the field
    public object Value { get; set; }   //The value of the field
}

I display a strongly-typed record view that shows StartTime in a form, but not Id. When a HttpPost happens, the controller method that handles HttpPosts for that view recieves a record that has the same Id as the original Record, but a StartDateTime of DateTime.MinValue.

Edit2: Does the way I'm displaying any model fields in the view have anything to do with what the controller HttpPost method will 'see' of the model?


Turned out it was the combination of a few things:

The view code I was using to display my StartDateTime field was not well structured enough for the default databinder to pick it up.

<input id="StartDateTime" type="text" value="<%= Model.StartDateTime.ToString("g") %>" />

That doesn't work. Neither does this

<input id="StartDateTime" type="text" value="<%= Model.StartDateTime %>" />

This works:

<%= Html.TextBoxFor(model => Model.StartDateTime)%>

The second issue is that my StartDateTime text field was disabled (had the html attribute disabled="disabled") - it's meant to be view only, but disabled fields don't return anything on a post (as mentioned here) so even if I did use the TextBoxFor HtmlHelper, it still wouldn't work. Thanks to everyone for the links, now I know a bit more about what the important attributes are in getting the databinding to work.


Are you looking for the implementation of the IModelBinder? There is a default IModelBinder

Is this what you were looking for?


Do you have a form field named StartDateTime? The default model binder matches the id's of the form fields to the property names in the view model. If you don't have a form field named StartDateTime, the model binder will not populate that property.

If you need to track the value but not display it, you can always use a hidden box on the page so that the value can be returned.

Also, it might just be having trouble because of the date and time components and the formatting used in the web page. Scott Hanselman has a blog post that might help.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号