【问题标题】:How bad is the following snippet?以下代码段有多糟糕?
【发布时间】:2009-02-11 20:33:08
【问题描述】:

我的问题很简单:下面的 sn-p 代码有多糟糕? 会怎么做呢?

CancelEventHandler _windowClosing;
private CancelEventHandler WindowClosing 
{
  set
  {
    clearEventHandlerList();
    this.Closing += value;
    _windowClosing = value;


    /*
     * if calling the method with null parameters,
     * it will set up itself as the primary control on the Window
     */
    _windowClosing(null,null);
  }
  get
  {
    return _windowClosing;
  }
}

private readonly CancelEventHandler[] CONTROLS = null;
private int current = 0;

public InitializerForm()
{
  InitializeComponent();

  /*
   * these are the handlers for the different controls,
   * in the order of appereance to the user
   */
  STATES = new CancelEventHandler[] { handler1, handler2, etc. };

  WindowClosing = CONTROLS[0];
}

private void clearEventHandlerList()
{
  foreach (CancelEventHandler c in CONTROLS)
  {
    this.Closing -= c;
  }
}

private void handler1(object obj, CancelEventArgs e)
{
  if (obj == null)
  {
    //hide every other control, but this one, also set up if necessary
  }
  else
  {
    //do something

    WindowClosing = CONTROLS[++current]; // set the next control to show

    e.Cancel = true;
  }
}

关键是代码不会关闭表单,而是在其上显示另一个组件,并设置处理方式(这是移动平台,因此单击顶部的确定按钮会生成关闭事件)。这是因为一个接一个地向用户显示多个表单(4 个或 5 个)会使应用程序闪烁,也很烦人,而仅替换组件则更加顺畅。这个模型有效,但看起来很讨厌,我想要一种更简洁的方法来处理这个问题。

更新: 我更新了代码示例,使变量名有点说话。不过,我确信这很糟糕,(a) 但不确定有多少,更重要的是,(b) 如何做得更好。

更新 2: 所以,看来代码还是有点神秘。

现在问题出在: 我向用户展示了一个表单,该表单以多种语言指示他该做什么。他继续单击窗口上的“确定”。接下来,我问他的语言,然后像这样的几个问题(他/她的 GPS 在哪里等)。在他回答完问题后(每个问题不应该超过几秒钟),我给他看一个启动画面(同时我在一个单独的线程中加载内容),上面有一张图片。一个接一个地显示这些表单会使整个应用程序启动缓慢,并充满 UI 滞后。

以下是我为解决滞后问题所做的工作:我将窗口的内容放入面板中,然后将这些面板一个接一个地放置,并隐藏除应该对用户可见的每个面板之外的每个面板。 (current 变量)每个窗口做不同的事情,所以我需要另外更改窗口closing 事件的处理程序。在此代码中,启用面板的部分与处理窗口关闭事件的部分具有相同的功能(handler1handler2 等)。如果参数是null,则执行前者,如果不是(这意味着它是由用户触发的),则执行后者。

我需要一个可扩展的解决方案,以便我可以随时插入和删除对话框(函数的顺序和指针存储在 CONTROLS 字段中,这似乎非常方便,如果你真的理解它。虽然改变表单的全部内容从来都不是一件容易的事,但应该有一种更简单的方法来做到这一点,而且还有一种更好的方法,这就是我正在寻找的。​​p>

我希望这次我能解释一下这个模型是如何工作的。

【问题讨论】:

  • 我建议您阅读一些 .NET 或 C# 编码指南。例如变量命名。我第二个 LDomagala...
  • 你为什么这么快地向用户展示 4 或 5 个表单?
  • 忘记上面的代码。你想达到什么目的?
  • +1:对于马特,告诉我们你想要做什么,我既没有时间也没有意志力去理解上述内容(无论如何也不是一时兴起,如果我也有的话......)
  • 哈哈,我不认为变量命名是上面代码的关键。

标签: c# windows windows-mobile mobile delegates


【解决方案1】:

我认为理论上可以使代码更令人愉快地转移注意力、危险地顽皮、快活地危险、愉快地冒险和不小心的异想天开,但这需要一些认真的思考。

【讨论】:

  • 对于标记此“冒犯性”的人:stackoverflow.com/questions/135685/… - 请注意,原始问题的标题是“以下内容有多糟糕......”所以这里有一个幽默元素,你可能错过了。
  • 好吧,措辞的选择可能会让你的回答变得令人反感。然而,不幸的是,这也是事实。
【解决方案2】:

不知何故,你的代码让我想哭,对不起。我读了两遍,我所知道的就是它“doesStuff”和“STATES”。

如果你真的需要这方面的帮助,你必须先自己动手......

【讨论】:

    【解决方案3】:

    使用,XML!它是人类可读的!

    更认真-

    您似乎正在尝试创建某种配置向导,所以我先研究一下。关于您的特定解决方案,我通常非常强烈反对“分层面板”方法。我这样做是因为我维护由发现这种方法的人编写的应用程序,或者相关的“选项卡控件上的隐藏选项卡”方法,这是一个好主意。不是,维护者会在未来几年诅咒你的名字。

    话虽如此,还有哪些选择?好吧,另一种选择是您已经忽略了它,因为它的“闪烁”。我想说,一般来说,对于快速而肮脏的应用程序来说,闪烁并不是什么大不了的事。例如,确保在关闭旧窗口之前调用新窗口可能是个好主意。 (我假设这是可能的,我还没有在移动设备上开发过。)

    另一种可能性可能是分层面板的不那么邪恶的版本。不要将六个面板放入一个表单中,而是为每个向导页面创建一个单独的用户控件,然后将用户控件添加/删除到包含的表单中。这可以避免闪烁,并且由于每个页面都处于不同的控件中,因此更容易维护。这也可能会简化任何后续的“后退”按钮功能并使您的数据结构更自然地定义,因为这些用户控件将与特定的逻辑数据位相关联。它仍然不理想,但对于一次性解决方案来说可能已经足够了。

    第三种技术,如果您预见到随着产品的成熟大量向导修改,则可能是通过以更具逻辑性/声明性的方式(例如通过 XML)定义用户控件来概括用户控件的创建.如果您基于 XML 动态生成合理的控件,那么修改面板可能就像潜入 XML 并执行以下操作一样简单:

    <Questions>
        <Question type="Text"> <!-- generate a textbox for the answer field -->
            Favorite Color:
        </Question>
        <Question type="Number" range="0-255"> <!-- Maybe this is a spinner -->
            The answer to life, the universe, and everything:
        </Question>
    </Questions>
    

    这只是我的想法,完全对于任何一次性应用程序来说都是多余的,但这是一种可能性。

    【讨论】:

      【解决方案4】:

      现在,让我警告这一点,说这可能有效,但它可能不是您真正问题的答案 - 当您有很多表单时,用户界面缓慢且无响应。真正的答案可能是继续执行所有单独的表单,但让每个表单在用户盯着第一个表单时在后台线程中加载其子表单。

      但假设您仍然对此有所准备,我将首先创建一个单独的类来处理面板堆叠/层次结构。称它为 PanelManager。您将实例化 PanelManager 并将其与主窗体相关联,然后将面板添加到其中(可能键入字符串)并设置顺序。在主窗体中,让关闭处理程序调用 PanelManager.CloseCurrentPanel(),如果没有更多面板要显示,那么是时候关闭主窗体了。

      伪代码的时间!这是该类的一个快速想法,我将留给您实现它:

      public class PanelManager {
      // constructor
      public PanelManager (Form ownerForm);
      
      // short-cut properties
      public Panel this[int idx]
      { get; set; }
      
      public int Index
      { get; set; }
      
      // main functionality
      
      public int AddPanel (Panel p);
      public void SetPanelOrder (Panel p, int idx);
      public void RemovePanel (Panel p);
      public void RemovePanelAt (int idx);
      
      // shows the first Panel
      public void Show ();
      
      // shows Panel[idx]
      public void Show (int idx);
      
      // adds the panel to the top of the stack and displays it
      // returns the index of the panel
      public int AddPanelAndShow (Panel p);
      
      // hides the current panel, displays the one underneath it
      // returns false if there are no more panels
      public bool HideCurrentPanel ();
      }
      

      在主窗体的构造函数中,通过new PanelManager(this)实例化它,然后在关闭事件处理程序中,调用panelManager.HideCurrentPanel(),然后判断是否需要关闭它。

      【讨论】:

      • 在 Greg D 建议之后,我实现了一个像你这样的模型,但具有更好的可扩展性(例如,加载和卸载面板的回调,它可以设置面板管理器的属性等),并且这个卡片布局结构似乎工作正常。无论如何,谢谢你的帮助!
      猜你喜欢
      • 1970-01-01
      • 2010-10-31
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-24
      • 2011-01-01
      相关资源
      最近更新 更多