【问题标题】:Having trouble understanding User Controls in C#无法理解 C# 中的用户控件
【发布时间】:2009-05-05 20:52:12
【问题描述】:
我是用户控件的新手,到目前为止只创建了一个,所以请多多包涵。我今天一直在阅读,用户控件应该是自包含的,不依赖于父容器中的任何信息。我明白了那部分,但我无法理解的是围绕该原则设计我的程序的“正确”方式。
我正在用 C# 制作一个 Web 表单,其中有一个页面,该页面中有一个用户控件。我已经在它的 ascx 文件中创建了 usercontrol 并将它拖到我的 aspx 页面中。用户控件是一对日期框和一个网格视图,用于显示 SQL 存储过程的结果。
我真的很想重用这个控件,但我不知道如何在不违反“不要”的情况下“告诉”用户控件我想为我所在的特定页面运行什么存储过程t 依赖于父容器”规则。
谢谢
【问题讨论】:
标签:
c#
user-controls
design-principles
【解决方案1】:
不依赖父容器不代表不能交流。在父级将设置的用户控件中公开一个属性。但是有一个默认值,所以它不会崩溃。
另外,如果这是一个非常具体的控件,那么依赖父控件没有理由不好。这可能并不理想,但您将使用用户控件来提供代码分离。
【解决方案2】:
您的控件不需要知道它的数据来自哪里。它不需要知道存储过程或其他任何事情。它只需要知道它需要显示的数据。如果我理解您的控制权,它是一个带有一些日期过滤器的网格。它将接收数据,显示该数据并按日期过滤。没关系,它只需要知道它需要显示的数据,也许还有来自父级的默认开始和结束日期。
【解决方案3】:
如果您不允许用户控件与其父级通信,您将错过用户控件的真正威力。在这种情况下,我认为您的封装可能有点过头了。
假设您有一个用户控件,它只是一个表格或各种用户数据的网格视图。不可避免地,用户控件需要知道用户的唯一标识符,以便从任何地方提取其数据,这当然会迫使您创建父页面可以设置的公共属性。
另外,请记住,有时用户控件中的操作需要触发父控件上的操作。事件委托在这里发挥了作用,它们非常有用,在我看来,它使用户控件更加有用。
只需放弃关于用户控件和父母不来回交谈的整个想法,您会发现事情变得容易得多。
【解决方案4】:
所以你在这个用户控件中有一些东西可以将数据绑定到存储过程返回的数据集?
这是处理它的一种方法:
与其尝试将存储过程传递给用户控件,不如创建用户控件依赖于用户控件的公共属性的数据集。
在运行时,用户控件之外的代码将运行适当的存储过程,并将用户控件上的数据集属性设置为存储过程返回的结果。
【解决方案5】:
正如其他人所指出的,您的用户控件需要有一种标准的方式来传达其意图和行为。这并不意味着您必须拥有对容器的引用,因此知道 (MyPage.aspx) 实际包含什么。
我发现在使用用户控件时必不可少的是事件。了解事件以及如何使用它们。事件是交流行为的好方法。
在您的示例中,我可能会将您的条件(日期文本框)拆分为自己的用户控件。创建一个继承自 EventArgs 的新类,其中包含您的条件(DateTime 字段)。当用户单击搜索时,使用您的自定义EventArgs 触发一个事件(EventHandler<YourEventArgs> 类型)。该页面将处理事件、查询数据库,然后将结果传递给您的第二个用户控件上的公共或内部方法,该方法会显示记录。
这里的关键是,如果您需要调用不同的存储过程,您的标准控件可以在不同的页面上重复使用。想想插入与更新场景。很多时候,UI 元素是相同的。您可以创建一个控件并在具有两种不同行为(AddRecord.aspx 和 UpdateRecord.aspx)的两个不同页面上使用它。此外,显示记录的控件非常容易重复使用。
一个巨大的好处是您的页面和控件变得相当小。每个控件/页面实际上只关心其一小部分功能。您的代码将变得不那么令人生畏并且更易于维护。
【解决方案6】:
“告诉”用户控件我想运行什么存储过程
听起来您正在寻找活动/代表
让控件公开一个事件,并让父级添加一个处理程序(可能在构造函数中,如果您想强制它添加一个且仅一个事件)
或者,您可以使用命令/策略模式 - 让父级封装方法,并将封装对象发送到其构造函数中的控件。