How to use webforms formview model binding for model with List of custom type

问题描述 投票:0回答:1

在 asp.net webforms 4.8 项目中,我使用 2 种方式模型绑定(到 FormView)。到目前为止,对于我的模型的标量属性和枚举来说一切都很好,但是对于我的主要模型的不是简单标量值的属性(比如其他对象的列表)来说,事情并不是很好。我有 3 个主要问题。

My SelectMethod 返回一个模型,该模型具有一个 List< AnotherCustomClass> 属性。使用中继器,此属性在 EditView 中呈现(只要 AnotherCustomClass 标记为 [Serializable])但在我的 UpdateMethod 中我遇到了问题 (1) - 该属性总是以 null 结尾。

我还创建了一个用于在列表中添加另一个项目的按钮,但是从代码隐藏方法我不知道如何 (2) 引用我的模型实例来添加新项目。问题 (3) 是,一旦该方法运行,我不知道如何使中继器再次呈现以查看我的新项目。 (理想情况下,这可以在不丢失对我的模型的任何其他未保存更改的情况下完成。)

这是一个演示我的问题的简化示例。我在这三个问题上花了几天时间,非常感谢有人指出正确的方向,因为我认为我只是在以错误的方式处理这个财产。

ASPX

<%@ Page Title="Home Page" Language="C#" AutoEventWireup="true" Inherits="ModelExample._Default" CodeBehind="~/Default.aspx.cs" %>
<html>
<head></head>
<body>
    <form runat="server" id="MainForm">
        <asp:FormView ID="frmVw" runat="server" DefaultMode="Edit"
            EnableModelValidation="true" ItemType="Models.PetModel"
            DataKeyNames="PetId"
            SelectMethod="frmVw_GetItem" UpdateMethod="frmVw_UpdateItem">
            <EmptyDataTemplate>
                No pet found, try adding ?PetId=11 as a query string parameter.
            </EmptyDataTemplate>
            <EditItemTemplate>
                <div id="EditPetDetails">
                    <div><h2>Pet Details:</h2></div>
                    <div>
                        <asp:Label runat="server" ID="lblPetName" Text="Name"></asp:Label>
                        <asp:TextBox runat="server" ID="tbPetName" Text="<%# BindItem.Name %>"></asp:TextBox>
                    </div>
                    <div>
                        <asp:Label runat="server" ID="lblDob" Text="Date of Birth"></asp:Label>
                        <asp:TextBox runat="server" ID="tbDob" Text='<%# BindItem.DateOfBirth %>' TextMode="Date"></asp:TextBox>
                    </div>
                    <div>
                        <asp:Label runat="server" ID="lblSpecies" Text="Species"></asp:Label>
                        <asp:DropDownList runat="server" ID="ddlSpecies" SelectMethod="ddlSpecies_Get" SelectedValue='<%# BindItem.Species %>'></asp:DropDownList>
                    </div>
                    <div>
                        <asp:Label runat="server" ID="lblWeight" Text="Weight (kg)"></asp:Label>
                        <asp:TextBox runat="server" ID="tbWeight" Text="<%# BindItem.Weight %>" TextMode="Number"></asp:TextBox>
                    </div>
                    <div>
                        <asp:Button runat="server" ID="btnSave" Text="Save" CommandName="Update" />
                    </div>
                </div>
                <hr />
                <div id="AddNotes">
                    <div>
                        <h2>Add Note:</h2>
                    </div>
                    <div>
                        <asp:Label runat="server" ID="lblNewNoteType" Text="Type"></asp:Label>
                        <asp:DropDownList runat="server" ID="ddlNewNoteType" SelectMethod="NoteType_Get"></asp:DropDownList>
                    </div>
                    <div>
                        <asp:TextBox runat="server" ID="tbNewNoteBody" TextMode="MultiLine"
                            Rows="5" Columns="50"></asp:TextBox>
                    </div>
                    <div>
                        <asp:Button runat="server" ID="btnAddNote" Text="Add Note" OnClick="btnAddNote_Click" />
                    </div>
                </div>
                <hr />
                <div id="NotesHistory">
                    <h2>Notes Histroy:</h2>
                    <asp:Repeater runat="server" ID="rptNotes" ItemType="Models.VisitNote" DataSource="<%# BindItem.VisitNotes %>">
                        <ItemTemplate>
                            <div>
                                <asp:Label runat="server" ID="lblNoteCreatedOn" Text="Date:"></asp:Label>
                                <asp:TextBox runat="server" ID="tbNoteCreatedOne" Text="<%# Item.CreatedOn %>" TextMode="Date" ReadOnly="true"></asp:TextBox>
                            </div>
                            <div>
                                <asp:Label runat="server" ID="lblNoteCreatedBy" Text="Author:"></asp:Label>
                                <asp:Label runat="server" ID="tbNoteCreatedBy" Text="<%# Item.CreatedBy %>"></asp:Label>
                            </div>
                            <div>
                                <asp:Label runat="server" ID="lblNoteType" Text="Type:"></asp:Label>
                                <asp:Label runat="server" ID="tbNoteType" Text="<%# Item.NoteType %>"></asp:Label>
                            </div>
                            <div>
                                <asp:TextBox runat="server" ID="tbNoteBody" Text="<%# Item.NoteBody %>"
                                    ReadOnly="true" TextMode="MultiLine" Rows="5" Columns="50"></asp:TextBox>
                            </div>
                        </ItemTemplate>
                    </asp:Repeater>
                </div>
            </EditItemTemplate>
        </asp:FormView>
    </form>
</body>
</html>

代码隐藏

using Models;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.ModelBinding;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ModelExample
{
    public partial class _Default : Page
    {
        private static List<PetModel> _pets = new List<PetModel>();
        protected void Page_Load(object sender, EventArgs e)
        {

            if (!_pets.Any())
            {
                var notesCollection = new List<Models.VisitNote>()
            {
                new Models.VisitNote() {
                    NoteId = 11, CreatedBy = "Jeanann Sutherland", CreatedOn = "2021-10-31",
                    NoteType = Models.NoteTypes.Intake,
                    NoteBody = "Pekoe has presented with sneezing, enflamed nose, nasal drainage and abnormaly clingy demeanor."
                }
            };
                _pets.Add(new Models.PetModel()
                {
                    PetId = 11,
                    DateOfBirth = "2014-07-24",
                    Name = "Pekoe",
                    Species = Models.PetSpecies.Cat,
                    Weight = 12.3f,
                    VisitNotes = notesCollection
                });
            }
        }

        public IEnumerable<string> ddlSpecies_Get()
        {
            return Enum.GetNames(typeof(Models.PetSpecies)).ToList<string>();
        }
        public IEnumerable<string> NoteType_Get()
        {
            return Enum.GetNames(typeof(Models.NoteTypes)).ToList<string>();
        }
        public Models.PetModel frmVw_GetItem([QueryString] int? PetId)
        {
            return _pets.FirstOrDefault(p=> p.PetId == PetId);
        }
        // The id parameter name should match the DataKeyNames value set on the control
        public void frmVw_UpdateItem(int? PetId)
        {
            Models.PetModel item = _pets.FirstOrDefault(p=> p.PetId == PetId);
            // Load the item here, e.g. item = MyDataLayer.Find(id);
            if (item == null)
            {
                // The item wasn't found
                ModelState.AddModelError("", String.Format("Item with id {0} was not found", PetId));
                return;
            }
            TryUpdateModel(item);
            // when updating the Notes property is null - where did the notes go?
            var notesCount = item.VisitNotes?.Count() ?? 0;
        }

        protected void btnAddNote_Click(object sender, EventArgs e)
        {
            //Desired behavior is - when user adds note the note is added to the VisitNote list of the model being edited
            //The repeater that displays the list should show the new note
            //The note sits in the model - logic in the Update method will find notes with default ID and insert as needed.

            //author info comes from logged in user
            var author = "Dr P Sorthes";
            //How do I pull the selected value from ddlNewNoteType and tbNewNoteBody ?
            //Googling find people casting a control found by calling the formview's find control method
            //is that really the right/best way to do this?
            var noteType = NoteTypes.Diagnosis;
            var body = "Where is the body?";

            //How do I get a reference to the current model the page is using?
            //if you debug at this point you'll see frmVw's DataItem and DataItemContainer are both null
            //though DataTimeCount is 1
            var pet = _pets.Where(p => p.PetId == 11).First();

            var oldNotes = pet.VisitNotes;

            //Try update throws:
            //System.InvalidOperationException: ''TryUpdateModel' must be passed a value provider or alternatively must be invoked
            //from inside a data-operation method of a control that uses model

            //TryUpdateModel(pet);

            pet.VisitNotes = oldNotes ?? new List<VisitNote>();

            pet.VisitNotes.Add(new VisitNote() { CreatedBy = author, NoteType = noteType, CreatedOn = DateTime.UtcNow.ToString("yyyy-MM-dd"), NoteBody = body });

            //What do I do to make the notes repeater show the newly added note?
        }
    }

}


namespace Models
{
    public class PetModel
    {
        private DateTime? dateOfBirth;
        public int PetId { get; set; }
        public string Name { get; set; }
        public string DateOfBirth { get { return dateOfBirth?.ToString("yyyy-MM-dd") ?? ""; } set { dateOfBirth = DateTime.Parse(value); } }
        public PetSpecies Species { get; set; }
        public Single Weight { get; set; }
        public List<VisitNote> VisitNotes { get; set; }
    }
    [Serializable]
    public class VisitNote
    {
        private DateTime? createdOn;
        public int NoteId { get; set; }
        public String CreatedOn { get { return createdOn?.ToString("yyyy-MM-dd") ?? ""; } set { createdOn = DateTime.Parse(value); } }
        public String CreatedBy { get; set; }
        public NoteTypes NoteType { get; set; }
        public String NoteBody { get; set; }
    }
    [Serializable]
    public enum NoteTypes
    {
        Intake,
        Diagnosis,
        Prescription,
        Followup
    }
    [Serializable]
    public enum PetSpecies
    {
        Dog,
        Cat,
        Bird,
        Fish,
        Snake
    }
}
c# asp.net .net webforms model-binding
1个回答
0
投票

还没有其他答案,所以我发布了我想出的最佳选择,以防其他试图解决这个问题的人稍后阅读。

我仍然希望我能找到一种方法来在单个表单视图中完成我的要求。

如果我使用 formview(在编辑模式下)来获取模型的简单属性,我可以接近第二个窗体视图显示现有笔记的历史记录。在第二个窗体视图的插入方法中,在中继器上调用VistNote,以便显示新插入的注释。我已经确认第一个表单视图中未保存的编辑在上述所有情况下都有效。

它是两个表单视图和一个中继器,而不是单个表单视图,并不像我想象的那么干净,但它确实有效。
ASPX
DataBind()

代码隐藏

<%@ Page Title="Home Page" Language="C#" AutoEventWireup="true" Inherits="ModelExample._Default" CodeBehind="~/Default.aspx.cs" %> <html> <head><title>Vet Example</title></head> <body> <form runat="server" id="MainForm"> <!--Main form view shows just the 1:1 properties - not the list of notes--> <asp:FormView ID="frmVw" runat="server" DefaultMode="Edit" EnableModelValidation="true" ItemType="Models.PetModel" DataKeyNames="PetId" SelectMethod="frmVw_GetItem" UpdateMethod="frmVw_UpdateItem"> <EmptyDataTemplate> No pet found, try adding ?PetId=11 as a query string parameter. </EmptyDataTemplate> <EditItemTemplate> <div id="EditPetDetails"> <div> <h2>Pet Details:</h2> </div> <div> <asp:Label runat="server" ID="lblPetName" Text="Name"></asp:Label> <asp:TextBox runat="server" ID="tbPetName" Text="<%# BindItem.Name %>"></asp:TextBox> </div> <div> <asp:Label runat="server" ID="lblDob" Text="Date of Birth"></asp:Label> <asp:TextBox runat="server" ID="tbDob" Text='<%# BindItem.DateOfBirth %>' TextMode="Date"></asp:TextBox> </div> <div> <asp:Label runat="server" ID="lblSpecies" Text="Species"></asp:Label> <asp:DropDownList runat="server" ID="ddlSpecies" SelectMethod="ddlSpecies_Get" SelectedValue='<%# BindItem.Species %>'></asp:DropDownList> </div> <div> <asp:Label runat="server" ID="lblWeight" Text="Weight (kg)"></asp:Label> <asp:TextBox runat="server" ID="tbWeight" Text="<%# BindItem.Weight %>" TextMode="Number"></asp:TextBox> </div> <div> <asp:Button runat="server" ID="btnSave" Text="Save" CommandName="Update" /> </div> </div> </EditItemTemplate> </asp:FormView> <!--Dedicated form view for adding a note. Not visible by default - shown in main form view's select method if a record is found.--> <asp:FormView ID="frmVwNotes" runat="server" DefaultMode="Insert" Visible="false" EnableModelValidation="true" ItemType="Models.VisitNote" InsertMethod="frmVwNotes_InsertItem"> <InsertItemTemplate> <hr /> <div id="AddNotes"> <div> <h2>Add Note:</h2> </div> <div> <asp:Label runat="server" ID="lblNewNoteType" Text="Type"></asp:Label> <asp:DropDownList runat="server" ID="ddlNewNoteType" SelectMethod="NoteType_Get" SelectedValue="<%# BindItem.NoteType %>"></asp:DropDownList> </div> <div> <asp:TextBox runat="server" ID="tbNewNoteBody" TextMode="MultiLine" Rows="5" Columns="50" Text="<%# BindItem.NoteBody %>"></asp:TextBox> </div> <div> <asp:Button runat="server" ID="btnAddNote" Text="Add Note" CommandName="Insert" /> </div> </div> </InsertItemTemplate> </asp:FormView> <!--Repeater shows readonly history of notes for selected pet--> <div id="NotesHistory"> <asp:Repeater runat="server" ID="rptNotes" SelectMethod="rptNotes_GetData" ItemType="Models.VisitNote"> <HeaderTemplate> <hr /> <h2>Notes Histroy:</h2> </HeaderTemplate> <ItemTemplate> <div> <asp:Label runat="server" ID="lblNoteCreatedOn" Text="Date:"></asp:Label> <asp:TextBox runat="server" ID="tbNoteCreatedOne" Text="<%# Item.CreatedOn %>" TextMode="Date" ReadOnly="true"></asp:TextBox> </div> <div> <asp:Label runat="server" ID="lblNoteCreatedBy" Text="Author:"></asp:Label> <asp:Label runat="server" ID="tbNoteCreatedBy" Text="<%# Item.CreatedBy %>"></asp:Label> </div> <div> <asp:Label runat="server" ID="lblNoteType" Text="Type:"></asp:Label> <asp:Label runat="server" ID="tbNoteType" Text="<%# Item.NoteType %>"></asp:Label> </div> <div> <asp:TextBox runat="server" ID="tbNoteBody" Text="<%# Item.NoteBody %>" ReadOnly="true" TextMode="MultiLine" Rows="5" Columns="50"></asp:TextBox> </div> </ItemTemplate> </asp:Repeater> </div> </form> </body> </html>

© www.soinside.com 2019 - 2024. All rights reserved.