如何复制If ...那么逻辑作为Web控件?

时间:2010-08-18 05:43:14

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

我有一位设计师在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>

3 个答案:

答案 0 :(得分:2)

而不是写控件

asp:If

为什么不使用:

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

答案 1 :(得分: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>

<asp:panel>可以更改为其他类型的网页控件,例如<asp:label>等。我认为几乎所有的网络控件都具有可见属性,因此您可以随时隐藏/显示它们。

答案 2 :(得分:0)

数据绑定语法有两个问题:首先是设计师与使用纯文本有点怪异,其次要求设计人员记住在“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”。

如果确实希望摆脱<%# %>,可以使用许多不同的技巧来利用CodeDOM或其​​他方式动态编译代码,尽管性能将是一个挑战,因为每次页面运行时你可能最终会动态编译代码,这可能会引入讨厌的安全问题等等。我会远离那个。