【问题标题】:How can I replicate If...Then logic as a Web control?如何将 If...Then 逻辑复制为 Web 控件?
【发布时间】:2010-08-18 05:43:13
【问题描述】:

我有一个在 ASPX 级别工作的设计师。他不做 C#,不做代码隐藏,不编译等。他是一个纯粹的设计师,使用 HTML 和服务器控件。

我需要一个条件控制——一个 If...Then-ish 类型的东西。通常,我会这样做:

<asp:Placeholder Visible='<%# DateTime.Now.Day == 1 %>' runat="server">
  It's the first day of the month!
</asp:PlaceHolder>

在没有数据绑定语法的情况下,有什么方法可以做这样的事情吗?比如:

<asp:If test="DateTime.Now.Day == 1" runat="server">
  It's the first day of the month!
</asp:If>

是否有某种方法可以扩展占位符以允许这样做?我摆弄了一下,但最后,我有一个条件,我基本上必须编译。

现在,数据绑定语法没有任何问题,但只是多了一点……奇怪,设计师必须理解。此外,它没有给我“其他”陈述。像这样的东西会很棒......

<asp:If test="DateTime.Now.Day == 1" runat="server">
  It's the first day of the month!
  <asp:Else>
    It's not the first day of the month!
  </asp:Else>
</asp:If>

【问题讨论】:

  • 如果我遇到了这个问题,我会放置两个面板控件,每个条件一个,自己设置它们各自的可见属性,然后告诉我的程序员正确地编写每个控件。这自然会导致我同时插入测试基础设施。

标签: asp.net custom-server-controls web-controls


【解决方案1】:

而不是写控件

asp:If

为什么不使用:

<% if expression
       { %>
    Yellow
    <% } %>
    <% else
        {%>
    Red
    <% } %>

【讨论】:

  • 请注意,如果表达式依赖于 Page_Load、回发代码等中生成的运行时数据,这将不起作用,因为上面的表达式在服务器端事件处理程序之前的页面生命周期的早期进行评估正在运行。
【解决方案2】:

考虑到代码隐藏文件已经出来了,因为设计师可能没有 VS,我认为更简单、代码更少的解决方案可能更优惠:

<%@ Page Language="C#"%>

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        if (DateTime.Now.Day == 1)
        {
            DateTestPanelFirst.visible = true;
            DateTestPanelOther.visible = false;
        }
    }
</script>

<html>
<body>

<asp:panel runat="server" id="DateTestPanelFirst" visible="false">
  It's the first day of the month!
<asp:panel>

<asp:panel runat="server" id="DateTestPanelOther">
    It's not the first day of the month!
<asp:panel>

</body>
</html>

&lt;asp:panel&gt; 可以改成其他类型的 web 控件,比如&lt;asp:label&gt; 等。我想几乎所有的点网控件都有可见属性,所以你可以随时隐藏/显示它们。

【讨论】:

    【解决方案3】:

    数据绑定语法有两个问题:首先,与使用纯文本相比,它对您的设计者来说有点奇怪,其次,它要求设计者记住在“else”块中反转“if”测试。

    第一个问题可能会让你的设计师有点恼火,但第二个问题要严重得多,因为它迫使你的设计师像程序员一样思考(反转布尔逻辑!)并使每个 if/else 块都成为你可能的错误需要在设计师交出模板后进行测试。

    我的建议:使用数据绑定语法,但通过创建自定义控件来解决更严重的问题,这些控件只需要在 If 控件上进行数据绑定测试代码,而不是在 Else 控件上。当然,您的设计人员将不得不输入更多字符,但其他更严重的问题将不适用,并且您的性能不会像每次运行页面时都必须动态编译代码那样受到影响。

    这是我编写的一个示例来说明:

    <%@ Page Language="C#"%>
    <%@ Register Assembly="ElseTest" TagPrefix="ElseTest" Namespace="ElseTest"%>
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            DataBind();
        }
    </script>
    
    <html>
    <body>
    
        <ElseTest:IfControl runat="server" visible="<%#1 == 1 %>">
            This should be visible (in "if" area) 
        </ElseTest:IfControl>
        <ElseTest:ElseControl runat="server">
            This should not be visible (in "else" area) 
        </ElseTest:ElseControl>
    
        <br /><br />
    
        <ElseTest:IfControl runat="server" visible="<%#0 == 1 %>">
            This should not be visible (in "if" area) 
        </ElseTest:IfControl>
        <ElseTest:ElseControl runat="server">
            This should be visible (in "else" area) 
        </ElseTest:ElseControl>
    
    </body>
    </html>
    

    这是底层控件,它们只是 asp:Literal 的包装器:

    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    [assembly: TagPrefix("ElseTest", "ElseTest")]
    namespace ElseTest
    {
        // simply renames a literal to allow blocks of data-bound-visibility
        [ToolboxData("<{0}:IfControl runat=\"server\"></{0}:IfControl>")]
        public class IfControl : Literal
        {
        }
    
        [ToolboxData("<{0}:ElseControl runat=\"server\"></{0}:ElseControl>")]
        public class ElseControl : Literal
        {
            public override bool Visible
            {
                get
                {
                    // find previous control (which must be an IfControl). 
                    // If it's visible, we're not (and vice versa)
                    for (int i = Parent.Controls.IndexOf(this)-1; i >= 0; i--)
                    {
                        Control c = Parent.Controls[i];
                        if (c is IfControl)
                            return !c.Visible;  // found it! render children if the if control is not visible
                        else if (c is Literal)
                        {
                            // literals with only whitespace are OK. everything else is an error between if and then
                            Literal l = c as Literal;
                            string s = l.Text.Trim();
                            if (s.Length > 0)
                                throw new ArgumentException("ElseControl must be immediately after an IfControl");
                        }
                    }
                    throw new ArgumentException("ElseControl must be immediately after an IfControl");
                }
                set
                {
                    throw new ArgumentException("Visible property of an ElseControl is read-only");
                }
            }
        }
    }
    

    如果您希望它更简洁,您可以轻松缩短标签名称(通过更改类名和/或标签前缀)。您还可以创建一个新属性(例如“test”)来代替“Visible”。

    如果您真的想要摆脱 &lt;%# %&gt;,您可以使用许多不同的技巧来利用 CodeDOM 或其他方式来动态编译代码,尽管性能将是一个挑战,因为您可能最终会在每次页面运行时动态编译代码,这可能会引入令人讨厌的安全问题等等。我会远离那个。

    【讨论】:

    • 不是我想要的,但经过深思熟虑,朝着正确的方向迈出了一步。
    猜你喜欢
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 2020-05-04
    • 2018-10-30
    • 1970-01-01
    • 2013-02-11
    • 1970-01-01
    • 2014-03-21
    相关资源
    最近更新 更多