以下片段有多糟糕?

时间:2009-02-11 20:33:09

标签: c# windows windows-mobile mobile delegates

我的问题很简单:下面的代码片段有多糟糕? 怎么做?

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

关键是代码不会关闭表单,而是显示另一个组件,并设置处理方式(这是移动平台,因此单击顶部的OK按钮会生成关闭事件)。这是因为向用户一个接一个地显示几个表单(4或5)使得应用程序闪烁,并且也非常烦人,而更换组件则更加顺畅。这个模型有效,但看起来非常讨厌,我希望有一种更清晰的方法来处理这个问题。

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

更新2: 所以,似乎代码仍然有点神秘。

现在问题是: 我向用户显示一个表单,指示他用多种语言做什么。他通过单击窗口上的确定继续。接下来,我问他的语言,然后问一些问题(他/她的GPS等等)。在他能够回答问题后(这不应该超过几秒钟),我向他展示了一个启动画面(我在一个单独的线程中加载东西),它有一张图片。一个接一个地显示这些表单使得整个应用程序开始变慢,并且填充了UI滞后。

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

我需要一个可扩展的解决方案,以便我可以随时插入和删除对话框(命令和指向函数的指针存储在CONTROLS字段中,这似乎非常方便,如果你真的理解它。尽管改变表单的整个内容并不容易,但应该有一种更简单的方法来做到这一点,以及一个更好的方法,这就是我正在寻找的。

我希望这次我可以解释模型是如何运作的。

4 个答案:

答案 0 :(得分:2)

我认为理论上可能会让这些代码更加令人愉快地转移,危险地顽皮,令人愉快地变得危险,快乐且不真实,但这需要一些认真思考。

答案 1 :(得分:1)

不知怎的,你的代码让我想哭,对不起。我读了两遍,而我所知道的就是它“确实”和“状态”。

如果你真的需要一些帮助,你必须先自己动手......

答案 2 :(得分:0)

使用,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>

这只是我的头脑, 完全 过度使用任何一次性应用程序,但这是可能的。

答案 3 :(得分:0)

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

但是假设你仍然坚持这一点,我首先要创建一个单独的类来处理Panel堆叠/层次结构。称之为PanelManager。您将实例化PanelManager并将其与主窗体关联,然后向其添加Panel(可能键入String)并设置顺序。在主窗体中,让闭包处理程序调用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 ();
}

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