1

想象以下场景 - 我们有 Page1,其中包含控件 Control A 和 Control B。

假设控件 A 有一个按钮,单击此按钮时我们希望控件 B 做出反应。但是我们想以一种抽象的方式来做这件事,即我们不能让控件 B 知道关于控件 A 的任何事情,反之亦然。

这样我们就可以单独开发这些控件,并通过单元测试来驱动它们。

现在,我以为我有解决方案,只是想知道你们对此有何看法。

单击控件 A 的按钮时,我在 Session 上放置了一条“消息”,即 Session["MESSAGES"] = "ControlA_Click"。

在 Page1 中,在 Page_LoadComplete() 上,我调用了 ProcessMessages,如下所示:

            List<Message> messages = SessionMessages.GetMessageList(Page);
        foreach(Message m in messages)
        {
            //Get Controls
            ControlA controlA = FindControl("controlA") as ControlA;
            controlA .ProcessMessage(m);

            ControlB controlB = FindControl("controlB") as ControlB;
            controlB.ProcessMessage(m);
      }

在 ControlB 的 ProcessMessage() 方法中,我们可以对 ControlB 感兴趣的消息做出反应,如下所示:

    if (m.MessageName == SessionMessages.C_MESSAGE_SEARCH)
{
    this.Visible = true;
}

对我来说,这似乎有效。它允许我们完全独立地开发这些控件,同时仍然允许在抽象级别进行控件间通信。

我能想到的唯一可能导致崩溃的可能是与页面和用户控件相关的 ASP.NET 生命周期。我认为它的方式是在拥有页面上调用 Page_LoadComplete() 之前,应该在控件上处理所有事件。

想法?

4

7 回答 7

6
  1. 控件 A 应该引发一个事件
  2. 包含控件的页面订阅事件,然后在另一个控件中调用适当的方法
  3. 控件 B 应该处理 message()
于 2008-11-11T18:08:49.807 回答
2

一个有趣的滥用会话......

您也可以让消息队列属于托管页面

我建议您让托管页面对控件进行一些操作以响应消息,而不是使控件变得“智能”-实际上不需要按钮“智能”

于 2008-11-11T18:03:14.980 回答
2

正如 Briggie 所暗示的那样——这正是 Model-View Presenter 的全部意义所在。这是一篇关于 .NET 中的 MVP 的文章,如果你想自己动手的话。

理想情况下,您希望将 MVC 框架视为将所有内容分离出来时可以做什么的示例。

我通常做的是让按钮单击事件引发特定于域的事件,例如:


private void ControlA_OnClick(..)
{
  if(LoginRequested != null)
    LoginRequested(this, loginObj);
}

这样就清楚地说明了为什么有人会单击按钮并将分离带回家。

于 2008-11-11T18:31:22.863 回答
1

这不是数据绑定的用途吗?控件 A 响应更新模型的事件,然后对其依赖项调用 databind。

如果你想做一个消息系统,设计它的发布者和订阅者不需要互相了解,只需要消息本身。创建一个类似的接口:

public interface IHandle<T> where T:IMessage
{
     void Process(T message)
}

您将需要一种方法来发现哪些控件实现了它并构建消息类型-> 处理程序的映射,查看主要 DI 框架处理对 ASP .NET 控件的属性注入的方式,以了解如何实现这一点。然后,您可以使用单个 SendMessage 方法,该方法负责将消息分派给可以处理该消息的所有控件。在表单 UI 中更常见的是这种模式。

于 2008-11-11T18:18:36.917 回答
1

你所拥有的几乎是一个EventBroker。我不认为 Session 是合适的地方,因为没有必要跨越请求。HttpContext可能有效,但除非我希望在 IHttpModules 和 IHttpHandlers 之间共享消息总线,否则我可能只是使用自定义控件可以将其 Page 实例转换为的基 Page 类:

interface IEventBroker {
 void Send(Message m);
}

class ControlA {
  void MyButton_Click(object sender, EventArgs e) {
     var eb = this.Page as IEventBroker;
     if (eb != null) eb.Send(new Message());
  }
}

或为控件提供对 EventBroker 的引用 - 在这种情况下,我可能会将 EventBroker 本身设为控件并将 ID 提供给每个控件,以便它们可以使用 Page.FindControl。

于 2008-11-11T21:03:58.297 回答
0

查看Managed Extensibility Framework Contrib 项目。他们只有一个示例网站,正是您想要的。

于 2008-11-11T18:16:15.890 回答
0

这种方法存在一些问题,例如:
- 编译时未验证“事件”(您很容易输入错误的事件名称并在运行时或更糟糕的情况下发现这一点)
- 用通信内容填充会话
- 您需要输入控件名称作为字符串 - 如果有多个控件是这些事件的订阅者,则可能会变得难以控制
- 当需要在控件之间发送参数时,解决方案将变得更加难以管理

更好的方法是通过在控件上声明事件来使用内置事件机制:

public event EventHandler SpecialClick;

每个需要做某事的控件都会订阅这个事件

controlA.SpecialClick += new EventHandler(controlA_SpecialClick)

使用正常的 dot.net 事件。

于 2008-11-11T18:19:00.660 回答