【问题标题】:ASP C# How to program neat GUI codeASP C# 如何编写整洁的 GUI 代码
【发布时间】:2009-04-06 09:49:58
【问题描述】:

大约几个月以来,我正在编写 ASP C#。我总是在事件中编写很多代码,在加载事件中我检查查询字符串是否有有效数据。这是我在一个项目中的一些示例代码:

protected void Page_Load(object sender, EventArgs e)
{
    if (Controller.Manual == null)
    {
        Response.Redirect("login.aspx");
    }

    lblLocation.Text = "<a href='viewdocument.aspx'>" + Controller.Manual.Title + "</a>";

    if (Request.QueryString["gchap"] != null)
    {
        if (Controller.IsNumeric(Request.QueryString["gchap"].ToString()))
        {
            genchap = Convert.ToInt32(Request.QueryString["gchap"]);

            FillGeneralList();

            SetChapterTitle();
        }
    }
    if (Request.QueryString["qchap"] != null)
    {
        if (Controller.IsNumeric(Request.QueryString["qchap"].ToString()))
        {
            qualchap = Convert.ToInt32(Request.QueryString["qchap"]);

            FillQualityList();

            SetChapterTitle();
        }
    }

    // Check document Id is set (did)
    if (Request.QueryString["did"] != null)
    {
        if (Controller.IsNumeric(Request.QueryString["did"].ToString()))
        {
            docId = Convert.ToInt32(Request.QueryString["did"]);

            DetermineView();
        }
    }

}

我知道必须有一种更简洁的方式来完成此任务。这只是加载事件。在其他事件上,例如 click 和 onchange 事件,我有类似的代码。我认为这是意大利面条代码,并且安排得不好。那么你能告诉我如何安排我的代码吗?

编辑:

我想知道的是,有没有更简洁的方法来填充列表框?我在哪里检查查询字符串值是否有有效数据?我在哪里检查(输入/查询字符串)数据是否是数字?您应该将验证查询字符串的代码放在哪里?也在加载事件中?

【问题讨论】:

    标签: c# user-interface refactoring


    【解决方案1】:

    我对 ASP.NET 网站的一些组织问题感到痛苦。我在几个项目中都有与您类似的代码。

    如果你可以选择你的框架,你可以看看 ASP.NET MVC。这允许您在视图(Html)、控制器(所有操作和业务逻辑)和模型(数据库)之间进行清晰的分离。这样一来,您的代码隐藏文件中的代码为零,所有这些都在控制器中保持整洁。

    【讨论】:

    • +1 ASP.NET Web 表单对于 winforms 转换程序员来说是一堆骇人听闻的骇客
    • +1 我完全同意。仅网络表单的设计就几乎不可能避免这种代码。您可以尝试在其上点焊一些类似 MVP 的图案,但这通常只会给您一种不同的意大利面条
    • @Martjin,是的,我愿意。下载它,然后在 Visual Studio 中创建“ASP.NET MVC Web 应用程序”。观看一些教程,您将学会喜欢它。这个站点 Stackoverflow 是用 ASP.NET MVC 制作的
    【解决方案2】:

    尝试使用 TryParse (for example),您可以简化所有看起来像的代码

    xx.IsNumeric(Request.QueryString["qchap"].ToString())
    

    Convert.ToInt32(Request.QueryString["gchap"]);
    

    并减少对Request.QueryString变量的调用次数

    你可以试试

    原始代码

    if (Request.QueryString["gchap"] != null)
    {
        if (Controller.IsNumeric(Request.QueryString["gchap"].ToString()))
        {
            gchap = Convert.ToInt32(Request.QueryString["gchap"]);
    
            FillGeneralList();
    
            SetChapterTitle();
        }
    }
    

    建议

    int? gchap; //nullable types thanks Richard :D
    if (!int.TryParse(Request.QueryString["gchap"], out id)) {gchap = null};
    
    if (gchap != null) {
         FillGeneralList();
         SetChapterTitle();
    }
    // you could make this neater with your own little method
    

    看看这个帖子How do you test your Request.QueryString[] variables?

    【讨论】:

    • 我建议使用可为空的 int (int?) 而不是错误场景的特殊值
    【解决方案3】:

    尝试在单独的函数中捕获重复代码。 (qchap / gchap)

    例如:

    qualchap = ConvertFillAndSet(Request.Querystring["qchap"]);
    genchap = ConvertFillAndSet(Request.QueryString["gchap"]);
    
    private int ConvertFillAndSet(string qrystring)
    {
      int numberToReturn = 0;      
    
      //if the conversion was ok -> true, else false
      if (Int32.TryParse(qrystring,numberToReturn))
      {
        FillQualityList();
        SetChapterTitle();
      }
    
      //returns 0 if tryparse didn't work
      return numberToReturn;
    }
    

    【讨论】:

      【解决方案4】:

      从哪里开始。不幸的是,尽管有其他 cmets,但您并没有真正编写任何特定于“网络表单”的内容。所以迁移到 MVC 并不会神奇地让你的代码变得更好。


      1 不要推出自己的身份验证:使用forms authentication,除非您有令人信服的理由不这样做。使用表单身份验证时,您无需在每个页面上编写代码来检查您是否已登录。框架会为您处理。


      2 Learn 使用server controls

      正如其他人所写的那样,您不应该在代码中编写 html,尤其是对于如此微不足道的事情。 Web 表单也不会让您这样做。

        <!-- this is in MyPage.aspx -->
        <asp:HyperLink id="viewLink" runat="server" />
      
        // in the code-behind file MyPage.aspx.cs
        viewLink.NavigateUrl = "~/viewdocument.aspx";
        viewLink.Text = Controller.Title;
      

      如果您要坚持使用网络表单,则需要熟悉ASP.Net Page life-cycle


      3 您的代码需要重构。无论是 Web 表单、php 还是 MVC。这里有一些基本的重构,这些都不是真正特定于 .net 的。我将逐步完成这些。

      // this may be a good candidate for an extension method
      int? ConvertNullable(string nullableInt) {
        if( string.IsNullOrEmpty(nullableInt) )
          return null;
      
        int value;
        if( Int32.TryParse(nullableInt, out value) )
          return value;
      
        return null;
      }
      

      然后你就可以写了。

      int genchap? = ConvertNullable(Request.QueryString["gchap"]);
      int qualchap? = ConvertNullable(Request.QueryString["qualchap"]);
      int docId? = ConvertNullable(Request.QueryString["did"]);
      
      FillQualityList(genchap,qualchap);
      SetChapterTitle(genchap,qualchap);
      DetermineView(docId);
      

      但是传递很多原语很麻烦而且容易出错,所以有时我们会做一个小类来封装数据,在这种情况下是页面初始化信息。

      class ChapterView
      {
        public int? GenChapter {get; set;}
        public int? QualChapter {get; set;}
        public int? DocumentId {get; set;}
      }
      
      private ChapterView GetChapterView()
      {
        return new ChapterView
        {
          GenChapter = ConvertNullable(Request.QueryString["gchap"]),
          QualChapter = ConvertNullable(Request.QueryString["qualchap"]),
          DocumentId = ConvertNullable(Request.QueryString["did"])
        }
      }
      

      请注意,我不知道 GenChap 和 QualChap 是什么,但它们有点简洁,您可以完成重构以使它们在代码中更具可读性。但即使没有更好的名字,我们现在也有了更易读的代码。

      ChapterView chapterView = GetChapterView();
      
      FillQualityList(chapterView);
      SetChapterTitle(chapterView);
      DetermineView(chapterView);
      

      最后你可能会确定你并不需要在每次页面执行时都调用它来读取查询字符串。如果您阅读过Asp.Net Page LifeCycle,您就会知道事件可能会更改GenChapter 或影响页面呈现方式的其他内容。您可能会发现在 PreRender 中设置视图比一遍又一遍地调用 FillQualityList 更好。

      ChapterView chapterView;
      
      Page_Load()
      {
        if( !IsPostback )
        {
          ChapterView chapterView = GetChapterView();
        }
        else
        {
          chapterView = (ChapterView) ViewState["chapterview"];
        }
      }
      
      NextChapter_Click()
      {
        chaperView.NextChapter();
      }
      
      Page_PreRender()
      {
        FillQualityList(chapterView);
        SetChapterTitle(chapterView);
        DetermineView(chapterView);}
      
        // make sure class is marked [Serializable]
        ViewState["chapterview"] = chapterView; 
      }
      

      【讨论】:

        【解决方案5】:

        您应该遵循分层方法。即:将所有数据访问代码放入数据访问层,将所有业务逻辑(也包括验证)放入业务层,将所有模型代码放入业务对象层

        最后是 ui - 尽量不要从代码中生成 html 标记。此外,始终为您的 aspx 页面创建一个根类,其中已经实现了常用方法。然后为每个其他 aspx 页面子类化这个根类

        如果您要在您的 c# 代码中对 html 标记进行硬编码 - 我可以向您保证,这总是会导致很多混乱(根据我自己的经验)

        但在某些情况下,您根本无法避免它。对于这种情况 - 这就是我所做的 - 我摆脱了背后的代码,只是将该代码放在我的 aspx / ascx 文件本身中。这样,当我必须根据永无止境的客户端请求更改我的用户界面时,我不必重新编译我的代码 - 我只需在登台/生产服务器上替换我的 aspx/ascx 文件。

        你知道客户是怎样的:嗯,你能不能让黑色条看起来有点像灰色,你能增加行间距,你能改变这个超链接的文本......像这样的请求似乎永远不会结束: -)

        【讨论】:

        • 我正在处理图层。我有表示层、业务层和数据层。也许我没有让自己足够清楚。在我的 startpost 中查看我的编辑
        • 嘿,martijn - 我已经更新了我的答案并提供了更多关于 ui 的详细信息 :-)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-05
        • 2021-11-17
        相关资源
        最近更新 更多