【问题标题】:How to declare an object using markup in ASP.NET如何在 ASP.NET 中使用标记声明对象
【发布时间】:2016-04-06 21:17:21
【问题描述】:

假设我们有一个Person 类:

public class Person
{
  public string FamilyName {get;set;}
  public string GivenName {get;set;}
}

还有一个控件可以以某种方式显示人员列表的信息。这是aspx的伪代码:

<uc1:EmployeesViewer runat="server">
  <Employees>
    <Person>
      <GivenName>John</GivenName>
      <FamilyName>Kerry</GivenName>
    </Person>
    <Person>
      <GivenName>Jack</GivenName>  
      <FamilyName>Lew</GivenName>
    </Person>
  <Employees>
</uc1:EmployeesViewer>

EmployeesViewer.Employees 的类型为List&lt;Person&gt;,属性为[PersistenceMode(PersistenceMode.InnerProperty)]

但是 Visual Studio 不编译这个。是否可以使用标记声明Person 对象?

【问题讨论】:

  • 为什么要这样做?这看起来很奇怪。
  • @jrummell 我们可以在代码隐藏中分配一个属性,对吧?我只是探索在标记中这样做的可能性,搜索了很多没有运气。
  • 那是因为它没有得到很好的支持,并且通常不鼓励,因为您的逻辑不应该在您的视图/页面中定义。但是,您可以在页面中嵌入 c# 代码,但这很难看。 msdn.microsoft.com/en-us/library/ms178135.aspx
  • @jrummell 这不是逻辑;这是我的静态数据。如何处理数据取决于EmployeesViewer,这是在代码隐藏中编写的。在 WPF 中,我们可以做到这一点,例如通过静态资源。即使在asp.net中,你解释写&lt;body&gt;&lt;form id="form1" runat="server"&gt;&lt;div&gt;可以吗?
  • @jstreet 谢谢,但我说的是 asp.net,而不是 HTML。

标签: c# asp.net webforms


【解决方案1】:

是否可以使用标记声明Person 对象?

是的,只是对标记进行了一些细微的更改(并且没有对您的 Person 类进行更改):

<%@ Page Language="C#" CodeBehind="DemoPage.aspx.cs" Inherits="DemoApp.DemoPage" %>
<%@ Register TagPrefix="uc1" Assembly="DemoApp" Namespace="DemoApp" %>

<uc1:EmployeesViewer runat="server">
    <Employees>
        <uc1:Person GivenName="John" FamilyName="Kerry" />
        <uc1:Person GivenName="Jack" FamilyName="Lew" />
    </Employees>
</uc1:EmployeesViewer>

uc1: 标记前缀假定您的 Person 类与 EmployeesViewer 位于相同的程序集和命名空间中。如果没有,只需&lt;%@ Register %&gt; Person 的另一个标签前缀。

注意:即使 Person 不是从 Control 派生的,您也可以使用 &lt;uc1:Person&gt; 语法:

namespace DemoApp
{
    public class Person
    {
        public string FamilyName {get;set;}
        public string GivenName {get;set;}
    }
}

这是一个简单的EmployeesViewer 控件,用于呈现员工列表:

namespace DemoApp
{
    [ParseChildren(true)]
    [PersistChildren(false)]
    public class EmployeesViewer : Control
    {
        private readonly List<Person> _employees = new List<Person>();

        [PersistenceMode(PersistenceMode.InnerProperty)]
        public List<Person> Employees
        {
            get { return _employees; }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            foreach (Person person in this.Employees)
            {
                writer.RenderBeginTag(HtmlTextWriterTag.P);
                writer.WriteEncodedText(string.Format("{0} {1}", person.GivenName, person.FamilyName));
                writer.RenderEndTag();
            }
        }
    }
}

需要[ParseChildren(true)] 属性,以便在运行时 ASP.NET 将&lt;Employees&gt; 标记解释为属性名称,而不是要呈现的文字标记。

需要[PersistChildren(false)][PersistenceMode(PersistenceMode.InnerProperty)] 属性,以便在设计时使用设计器的“属性”窗口修改Employees 集合时,Visual Studio 会正确地将集合保存到标记中。

【讨论】:

  • 正如我在另一条评论中所问的那样,所有解决方案都倾向于创建控件或用户控件。 标记中写入的所有标签是否必须是Control或其派生类类型?
  • 没有。使用这种方法,Person 不需要从 Control 派生。 (您仍然需要在标记中使用标记前缀,以便 ASP.NET 可以定位 Person 类的程序集和命名空间。)
  • 你能给我完整的标记,尤其是注册指令吗?我可以将 Person 和 EmployeesViewer 放在一个文件中吗?
  • 我已经用我完整的 .aspx 页面更新了这个答案,以及 Person 和 EmployeesViewer 类的示例命名空间。 (.aspx.cs 代码隐藏仅包含 DemoApp 命名空间和一个空的 public partial class DemoPage : Page 声明。)是否将 Person 和 EmployeesViewer 放在同一个文件中取决于您。你在让它工作时遇到问题吗?
  • 个人类作品。现在我添加了&lt;%@ register TagPrefix="sys" Assembly="System" Namespace="System" %&gt; 并将&lt;sys:Version /&gt; 放入 中,并将列表类型更改为System.Version,但编译器显示“Unknown server tag 'sys:Version'。”。你知道为什么吗?
【解决方案2】:

除了学术原因之外,我不确定您为什么要这样做。由于其他一些海报主要关注使用控件来创建标记,为什么不使用 DataSet 之类的东西来实现您想要实现的目标呢?

您可以通过从上下文菜单中的 Add > New Item > Data >DataSet 中选择 DataSet 来创建数据集。数据集可以是强类型并为您提供完整的智能感知功能,但这可能不适合您的方案。只是想我会把这个想法扔出去。

使用数据集:

流程:创建DataSet,创建DataTable,为DataTable创建列(DataColumns),实例化并绑定到给定的.aspx控件。

标准数据集/数据表/数据列:

DataSet ds = new DataSet("MyDataSetNameSpace");
DataTable person = new DataTable();
//add columns to the datatable
person.Columns.Add(new DataColumn(typeof(string)), "FamilyName");
person.Columns.Add(new DataColumn(typeof(string)), "GivenName");

强类型数据集:

PersonDataSet personDs = new PersonDataSet("PersonDataSetNameSpace");
//DataTable should already exist in your strongly-typed DataSet because you define the datatables in the vs designer
//accessing the datatable
personDs.Person person = new PersonDataSet.Person();
person.GivenName = "John Eisenhower Smith";
person.FamilyName = "Johnny";//nickname?  I'm guessing this might actually be Smith

如果您想在 Markup 中使用 DataSet,您可以将它绑定到您尝试创建列表的特定列表控件。

//you can define the DataSource in Markup or in CodeBehind.  You'd have to define a protected or public variable so that you can access the item in your markup.
//In markup, you would set DataSource = <%# Person%>
myGridViewControl.DataBind();//bind the dataset/datatable to the control

MSDN 参考:

https://msdn.microsoft.com/en-us/library/ss7fbaez(v=vs.110).aspx

编辑:

要完成您使用 XAML 完成的任务,您必须通过使用 Silverlight 控件来注入 XAML。有关如何执行此操作的更多信息,请参阅此帖子:

Is there a way to insert Silverlight XAML into my page using ASP.NET code-behind?

简短的回答是在 WebForms 中,目前无法完成。您必须使用 hack 来完成此操作,因为该框架不支持它。您可以使用 C# 代码块来执行您想要执行的操作,但您仍然无法正确完成您想要完成的操作。

【讨论】:

  • 所以学术上的原因是WPF可以在XAML中创建对象,有很多文章可用,例如。 How XAML works - Creating Objects With XAML。如果在 WPF 上下文中,我相信你们不会告诉我创建用户控件。
  • Ahhhh...tbh 我对 XAML 不是很熟悉...更多的是 WinForms/WebForms 人。我想不出任何东西可以帮助您在 ASP.NET 甚至 Java EE 中的 XAML 中完成您能做的事情(尽管我的知识在这里也很有限 - Java EE)。让我做更多的研究,看看我能想出什么。
  • 这篇文章通过使用 silverlight 控件将 XAML 注入 ASP.NET。我知道这不是您正在寻找的,但这是我能做的最好的。大多数其他海报只是建议使用带有自定义控件的 ASP.NET WebForms。我已在原始帖子中添加了帖子和编辑内容。
【解决方案3】:

你不能将 Person 作为用户控件吗? 并这样添加:

<uc1:EmployeesViewer runat="server">
    <Employees>
        <uc1:Person GivenName="John"/>
    </Employees>
<uc1:EmployeesViewer/>

编辑

做了一个测试示例。 将以下内容添加到 employeesView 以便能够访问标记中的人员:

Private _emptyDataTemplate As New List(Of Person)
    <Browsable(False)>
    <PersistenceMode(PersistenceMode.InnerProperty)>
    <TemplateContainer(GetType(Person))>
    Public ReadOnly Property Persons() As List(Of Person)
        Get
            Return _emptyDataTemplate
        End Get
    End Property

创建了一个 Person 类:

Public Class Person
    Inherits System.Web.UI.UserControl

    Private msFirstName As String
    Public Property FirstName() As String
        Get
            Return msFirstName
        End Get
        Set(ByVal value As String)
            msFirstName = value
        End Set
    End Property
End Class

在 main.aspx 中,我将其添加到标记中:

<!-- top of page -->
<%@ Register TagPrefix="pd" TagName="Person" Src="Person.ascx" %>
<%@ Register TagPrefix="pd" TagName="pView" Src="WebUserControl1.ascx" %>

<!-- wherever you use employeesView -->
<pd:EmployeesView ID="PView1" runat="server">
    <Persons>
        <pd:Person ID="Person2" FirstName="blabal" runat="server"></pd:Person>
        <pd:Person ID="Person3" FirstName="bobba" runat="server"></pd:Person>
    </Persons>
</pd:EmployeesView>

希望对你有帮助:)

【讨论】:

  • 是的,我可以。但这是我的业务对象。是否需要再创建一个 PersonUserControl?
  • 好吧,如果有可能你总是可以将你的 Person 类派生为一个新类,也可以从 Usercontrol 派生,这样你就可以保留你当前的 Person 类特性
  • 标记中写的所有标签是否必须是Control类型或其派生类?
  • 老实说,在这方面没有比您更多的经验。我试图注册一个 xxx.vb 文件,但它无法注册它,尽管 .vb 文件中的类是 UserControl 类型。所以我猜 .ascx 文件一定有什么东西。
  • 如果我不能使用UserControl,至少我无法解决它。但其他人可能知道方法。
【解决方案4】:

是的,有可能。

<% Person person1 = new Person();
   person1.FamiliName="Brown";
   person1.GivenName="John";
   List<Person> persons = new List<Person>();
   persons.Add(person1);
   EmployeesViewer.DataSource = persons;
%>

【讨论】:

    【解决方案5】:

    这是可能的。然而,它完全是它自己的动物。虽然这种方法全是微软的,但令人惊讶的是它被广泛采用。

    您可以使用xsd style sheets 来格式化数据。然后你插入一个对象,它会渲染那个对象。在某些版本的visual studio中,甚至还有generating样式表中的对象模型的方法。

    GL

    【讨论】:

    • 你明白我的问题吗?在代码隐藏中,我们知道我们可以写EmployeesViewer.Employees.Add(new Employee()) 来实现相同的功能,但我想写在标记中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 2016-03-06
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-20
    相关资源
    最近更新 更多