各位高人:
  菜鸟一枚,请问如下问题:
  工具栏上有一个确定按钮,在不同的子窗口下,点击“确定”按钮实现不同的处理。即:同一个确定按钮如何处理,在不同的子窗口界面下的情况。举例如:
   如果当前激活子窗口为“查询工单”,我点击确定,就调用相应的函数查询工单;若当前激活子窗口为“查询客户”,就去查客户。
   如果用类似if。。else的语句似乎能处理,总觉不太好,是否有更好的处理模式?请高人出手!

解决方案 »

  1.   

    1.写一个类继承Form类,如BaseChildForm,其中有个方法,  如ButtonClick
    2.每个子窗体继承BaseChildForm,重写ButtonClick方法,内容为“确定"按钮点击事件内容
    3.在父窗体中的”确定“按钮事件中写baseChildForm.ButtonClick();//baseChildForm为子窗体类对象
      

  2.   

    楼上的方法蛮好的,类似于依赖注入(DI),还有一种方法就是使用委托(delegate),我就针对委托写个例子吧,比如:
    我当前菜单是:
    Menu currentMenu = Menu.Menu1;
    在不使用委托的时候你需要写if else或者switch语句:
            static void TestWithoutDelegate(Menu menu)
            {
                switch (menu)
                {
                    case Menu.Menu1:
                        Console.WriteLine("菜单1");
                        break;
                    case Menu.Menu2:
                        Console.WriteLine("菜单2");
                        break;
                    case Menu.Menu3:
                        Console.WriteLine("菜单3");
                        break;
                    default:
                        break;
                }
            }
    然后调用之:
    TestWithoutDelegate(currentMenu);如果使用委托,那么你就需要多写几个方法,类似于:
            static void Menu1()
            {
                Console.WriteLine("菜单1");
            }        static void Menu2()
            {
                Console.WriteLine("菜单2");
            }        static void Menu3()
            {
                Console.WriteLine("菜单3");
            }
    然后客户端点击了哪个菜单,就使用委托来调用,类似于:
            static void TestWithDelegate(Test del)
            {
                del();
            }
                Test test = Menu1;
                TestWithDelegate(test);
      

  3.   

    兄台:
    问些比较菜的问题。
    当某个子窗体被激活时,就调用相应子窗体的处理函数。那这个激活,是.net框架或者操作系统自动将BasechildForm 实例化为那个窗体了?
    思来想去,不知道是谁让该类的多态性完成了这个操作。
      

  4.   

    小弟愚笨,对委托理解的很差。兄的方法有些懵懂,再问的深入一些。
    1.兄的方法似乎是类似于事件处理。具体一下场景:主窗体工具栏按钮上有个“执行”按钮,当不同的子窗体激活时,执行相应子窗体的功能。 于是代码示例如下:
     主窗体:Main
       1。定义委托  public delegate void ExecuteEventHandler(object sender, EventArgs e);
       2. 定义事件
           public event ExecuteEventHandler Execute;
        
           /// 执行按钮事件触发函数
            private void OnExecute(EventArgs e)
            {
                if (this.Execute != null)
                    this.Execute(this, e);
            }
          
            /// 点击“执行”按钮事件,触发执行事件
            private void tsBtnExcute_Click(object sender, EventArgs e)
            {
                EventArgs ee = new EventArgs();
                OnExecute(ee);
            }
      子窗体:侦听事件+处理函数
         
          ExcuteQueryOrder(objest sender,   EventArgs e)
         {
            从 参数e中拆解出主窗体送来的参数,执行查询工单
         }
         
         还要在子窗体中为主窗体登记这个处理函数,
         Main.Execute += new ExecuteEventHandler(this.ExcuteQueryOrder)
     
      首先请兄看一下这个写法是否正确,菜鸟妄言多有错误。2. 如果上述正确,接下来问题来了,每个子窗体都需要获得主窗体的实例才行,否则无法为主窗体登记事件处理函数。同时,这样用委托的目的不就是减轻耦合么,如果还需要获得主窗体的实例,岂不是有悖于初衷了?3.附加问题,如果子窗体需要工具栏上其他输入框如:Textbox输入的东西,且不同的子窗体需要的参数不尽相同,比如查工单需要日期段,查客户需要编号段,而这些又都在主窗体的工具栏上,该如何传递给子窗体呢?问题有点多,高手们见笑了。
         
      

  5.   


    你的问题非常好。我认为这正好说明勤于动手的人,很快就会超过只动嘴不动手的人。实际上,正如你说,所谓“事件”再此处成了一个噱头,把原本不应该“依赖倒置”的关系硬要倒置过来,反而要求“倒置之后再倒置回来”,反而使得原来的干净的分层关系变得乱起来了。回到你的最初的问题我们可以简单地分析名词和动词,看看对象(类)建模。什么是“当前查询子窗口”呢?你可以设计一个接口public interface 当前查询子窗口
    {
        void Query();
    }然后你的主窗口可以判断“当前窗口”是不是查询子窗口,例如var win = ActivedForm as 当前查询子窗口;
    if(win!=null)
        win.Query();
    这样的编程模式,仅仅比所谓的“条件分支、循环语句”稍微复杂一点,只不过这与基本的控制流语句相比稍微接触一点设计,并不复杂。
      

  6.   

    你的问题3跟问题2是一样的。作为一个框架,它往往控制着高层次的数据,而动态地加载不同类型的组件到自己内部。你可能写    var ca = your_control as IRequireDatasA;
        if(ca !=null)
            ca.SetDatas(this.DataA);
        var cb = ctrl as IRequireDatasB;
        if(cb !=null)
        {
            cb.SetDatas(this.DataB);
            cb.Saved += cb_Saved;
        }
        var cc = ctrl as IRequireDatasC;
        if(cc !=null)
            vc.SetDatas(this.DataC, others);
    也就是说如果子控件需要什么功能,那么它就让自己实现相应的接口,于是你的主程序就自动跟它协同了。
      

  7.   

    ctrl as  -->   your_control as
      

  8.   

    兄对问题2的解答非常精彩,解开了我的困惑。
    但对于工具栏上控件的值传入子窗口,还是不甚理解。详细描述一下。
    工具栏有若干控件:日期控件、组合框、Checkbox。
    子窗口一:只需要日期控件和组合框的内容;
    子窗口二:只需要组合框和Checkbox的内容。
    需要主窗口获得这些控件的值,通过“执行”按钮传入相应的子窗口。
    兄台的下述代码,不是太理解。个人感觉,将所有控件值都作为参数全部传入接口方法似乎是可以的。比如:
    ExeCute(DataTime , ComBox, CheckBox)
    不同的子窗口在重载Execute时,只需取出自己需要的控件值就可以了。但是,这个方法似乎有些笨拙,如果控件很多呢?好像没有体现出代码的自适应性。不知是否有更好的解决方案,请兄台解惑。
    再次拜谢!
      

  9.   

    你的程序架构是分层的,就好像vs可以加载不同的窗口,这些窗口可以停靠,可以布局,不同类型源代码的编辑窗口相应地可以执行不同的功能(例如从vs的菜单上选择“格式化”就会看到xml格式化跟cs格式化有所不同)。那么你设计一个UI框架时,你就是独立地定义出“我这个框架可以动态加载哪些窗口”,而不用让人去操作新这个vs上都有哪些菜单项(或者控件)。例如你为可以加载进来的子窗口预定义了5种业务类型,定义出5个interface,那么你的UI框架程序不用去操心子窗口内部有什么样的控件,子窗口的设计者(可能也是你本人)不用去操心调用它的UI框架是用什么控件来响应用户操作的。这里边不考虑具体的关于“控件”的技术,需要的就是业务接口。定义好接口,以一种初始设计的用户操作体验来“走通”接口调用规范。实际开发时人家子窗口,不用CheckBox而是用随时换了别的控件,那会随着用户需求变化而千变万化。而你的UI框架跟子窗口的交互规范并不变。所以我不谈你的UI窗口用什么控件、子窗口利用什么控件。我们就谈如何定义下程序骨架,以后当各种窗口内的控件都会千变万化地重构时,什么才是不变的规范。
      

  10.   

    其实设计也没有什么特别的技巧,就是考验你的测试用例。如果你已经想到“子窗口、UI框架窗口内的控件可能随时改变”,那么就毅然决然地在接口上用更加通用的数据类型来表示,不再涉及控件了。通常,也不会在接口上涉及任何UI控件。
      

  11.   

    有两种办法:
    1 子窗口都从自定义的 formbase 继承,在 formbase 中写些虚方法,子窗口重载这些方法,点击按钮的时候把子窗口转换成 formbase 就行了。
    2 子窗口都实现自定义的 iform 接口,在接口中写方法,子窗口转换成 iform 也行。
    另外,如果子窗口转换为相应的父类或者接口为空,则可以禁用按钮,效果最好。
      

  12.   

    兄台站的高度比较高,我大致能理解您的意思。这个如果我没理解错的话,就是界面其实应该与业务规范(或者说实际的数据)分开的。控件与其代表实际的数据可以说是要在逻辑上分离。
    我上面说的例子只是进行了简化,并不是说要用控件作为传入参数。我感觉现在最想不通的就是:
    一个UI框架中,主窗体到底如何子窗体交互。这么说似乎有点宽泛,更具体一点就归结为上面的问题,就是当不同的子窗体需要不同的数据参数时,主窗体是可以从控件上获得这些值的,而子窗体是不能的,但是如何传递给子窗体?上面有个兄弟说定义全局变量,这确实是个方法,子窗体是可以获得的,但是全局变量感觉耦合就太强了。
    我只是想知道高人们在编写UI框架时,到底是如何设计,怎么让主窗体与子窗体进行交互的。再次拜谢各位的回复!多谢各位的耐心回答。