简体   繁体   English

ASP C#如何编写简洁的GUI代码

[英]ASP C# How to program neat GUI code

For about a few months i'm programming ASP C#. 大约几个月我正在编写ASP C#。 I always program a lot code in the events and in the load event i check the querystring for valid data. 我总是在事件中编写很多代码,在load事件中我检查查询字符串是否有效数据。 This is some sample code i have in one of my projects: 这是我在其中一个项目中的一些示例代码:

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();
        }
    }

}

I know there must be a way to accomplish this on a more neat way. 我知道必须有一种方法可以更简洁的方式实现这一目标。 And this is just the load event. 这只是加载事件。 On other events, like click and onchange events i have similar code. 在其他事件上,例如click和onchange事件,我有类似的代码。 I think this is spaghetti code and not well-arranged. 我认为这是意大利面条代码并没有很好的安排。 So can you tell me how i can arrange my code? 所以你能告诉我如何安排我的代码吗?

EDIT: 编辑:

What i want to know is, is there a more neat way to, let's say, fill a listbox? 我想知道的是,是否有更简洁的方法,比方说,填写一个列表框? And where do i check whether a querystring value has valid data? 我在哪里检查查询字符串值是否有有效数据? Where do i check whether the (input/querystring) data is a number? 我在哪里检查(输入/查询字符串)数据是否是数字? And where should you put the code that validates the Querystring? 你应该在哪里放置验证Querystring的代码? Also in the load event? 还在加载事件中?

I feel your pain with some of the organization issues with ASP.NET websites. 我对ASP.NET网站的一些组织问题感到痛苦。 I've had similar code to yours on several projects. 我在几个项目上都有类似的代码。

If you have the choice of your frameworks you might look into ASP.NET MVC. 如果您可以选择框架,那么您可以查看ASP.NET MVC。 This allows you to have clear separation between the View (Html), the Controllers (All actions and business logic) and the Model (database). 这使您可以在View(Html),控制器(所有操作和业务逻辑)和Model(数据库)之间进行清晰的分离。 That way you have zero code in your codebehind files, it all stays nice and neat in controllers. 这样你的代码隐藏文件就没有代码了,它在控制器中保持良好和整洁。

Try using TryParse ( for example ) and you can simplify all the code that looks like 尝试使用TryParse( 例如 ),您可以简化所有看起来像的代码

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

and

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

and reduce the number of calls to Request.QueryString variables 并减少对Request.QueryString变量的调用次数

You could try something like 你可以试试像

Original code 原始代码

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

        FillGeneralList();

        SetChapterTitle();
    }
}

Suggestion 建议

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

Have a look at this post How do you test your Request.QueryString[] variables? 看看这篇文章你如何测试你的Request.QueryString []变量?

Try capturing the repetitive code in a separate function. 尝试在单独的函数中捕获重复代码。 (qchap / gchap) (qchap / gchap)

eg: 例如:

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;
}

Where to start. 从哪儿开始。 Unfortunately despite other comments, you're not really writing anything that is 'web forms' specific. 不幸的是,尽管有其他评论,但你并没有真正写出任何特定的“网络表单”。 So moving to MVC isn't going to magically make your code better. 所以转向MVC并不会让你的代码变得更好。


1 Don't roll your own authentication: Use forms authentication unless you have a compelling reason not to. 1不要滚动您自己的身份验证:使用表单身份验证,除非您有令人信服的理由不这样做。 When using forms authentication, you don't need to write code on every page to check that you're logged in. The framework handles that for you. 使用表单身份验证时,您无需在每个页面上编写代码来检查您是否已登录。框架会为您处理。


2 Learn to use the server controls : 2 学习使用服务器控件

Also as others write you shouldn't be writing html in code, especially for something so trivial. 另外,正如其他人写的那样,你不应该在代码中编写html,特别是对于那些微不足道的东西。 Web forms doesn't make you do this either. 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;

If you're going to stick with web forms, you need to get familiar with the ASP.Net Page life-cycle 如果您要坚持使用Web表单,则需要熟悉ASP.Net页面生命周期


3 Your code is in need of refactoring. 3您的代码需要重构。 No matter if it's web forms, php, or MVC. 无论是Web表单,php还是MVC。 Here are some basic refactorings, and none of this is really .net specific. 这里有一些基本的重构,而这些都不是.net特定的。 I'll walk through these in small steps. 我将逐步完成这些步骤。

// 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;
}

which then allows you to write. 然后允许你写。

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);

but passing a lot of primitives around is a hassle and prone to errors, so sometimes we make a small class to encapsulate the data, in this case the page initialization information. 但传递大量原语是一件麻烦事,容易出错,所以有时我们会创建一个小类来封装数据,在这种情况下是页面初始化信息。

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"])
  }
}

Note that I've no idea what GenChap and QualChap are, but they're a bit terse and you could complete the refactoring to make them more readable in code. 请注意,我不知道GenChap和QualChap是什么,但它们有点简洁,你可以完成重构,使它们在代码中更具可读性。 But even without better names, we now have more readable code. 但即使没有更好的名字,我们现在拥有更多可读代码。

ChapterView chapterView = GetChapterView();

FillQualityList(chapterView);
SetChapterTitle(chapterView);
DetermineView(chapterView);

And finally you may determine that you don't really need to call this every time the page executes to read from the query string. 最后,您可以确定每次页面执行时都不需要调用它来从查询字符串中读取。 If you've read up on the Asp.Net Page LifeCycle you know that events may change GenChapter or something else that affects how the page is rendered. 如果您已经阅读了Asp.Net Page LifeCycle,您就会知道事件可能会更改GenChapter或其他影响页面呈现方式的内容。 You may find it better to set up the view in the PreRender instead of calling FillQualityList over and over again. 您可能会发现在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; 
}

you should follow layered approach. 你应该遵循分层方法。 ie: put all your data access code in data access layer, put all your business logic (which also includes validations) in your business layer, put all your model code in your business object layer 即:将所有数据访问代码放入数据访问层,将所有业务逻辑(也包括验证)放在业务层中,将所有模型代码放入业务对象层

and finally for ui - try to never generate html mark up from within the code as far as possible. 最后为ui - 尽量不要在代码中生成html标记。 also, always create a root class for your aspx pages where it has common methods already implemented. 此外,始终为您的aspx页面创建一个根类,其中已经实现了常用方法。 then subclass this root class for every other aspx pages 然后为每个其他aspx页面子类化这个根类

if you are going to hardcode html markup within your c# code - i can assure you this would always result in a lot of chaos (based on my own experience) 如果你要在你的c#代码中硬编码html标记 - 我可以向你保证这会导致很多混乱(基于我自己的经验)

but there are situations where you simply cant avoid it. 但有些情况下你根本无法避免它。 for such cases - this is what i do - i get rid of the code behind and simply put that code in my aspx / ascx file itself. 对于这种情况 - 这就是我所做的 - 我摆脱了背后的代码,只是把代码放在我的aspx / ascx文件本身。 that way when i have to change my ui based on never ending client requests, i dont have to recompile my code - i simply replace my aspx / ascx files on the staging / production server. 这种方式当我必须根据永不停止的客户端请求更改我的UI时,我不必重新编译我的代码 - 我只需在登台/生产服务器上替换我的aspx / ascx文件。

you know how clients are : hmmm can u make the black strip look a bit like gray, can u increase the spacing between lines, can u change the text of this hyper link... requests like these never seem to end :-) 你知道客户是怎么回事:嗯,你可以让黑条看起来有点像灰色,你可以增加线之间的间距,你可以改变这个超链接的文本......像这样的请求似乎永远不会结束:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM