这是一个有趣的问题
我保证某些聪明的编程好手会建议我使用委托
在这种事情发生之前
让我们 先探究一下这个问题的几种解决方案
假定我有两个窗体每个窗体都有两个 textbox 控件txtstData 和 txtndData我怎样才能保持这两个窗体中的控件同步呢?对于我们讨论的问题来说有两个或十个窗体都不重要问题是相同的
第一个办法相对简单事实上它甚至比我们直接使用委托更为简单我想委托有时会给人用牛刀杀鸡的感觉首先我建立一个类它包含我希望与应用程序中的所有窗体共享的属性(参见 Figure )例如MyData 和 MoreData 拥有每个窗体都能显示的数据我将很快回到这个类来
第二正如我早先提到的我用相同的控件(txtstData 和 txtndData)建立了两个窗体你可以参考 Figure 的布局两个窗体都有完全相同的数据并且我将很快解释为什么
下面
我建立一个名为 modGeneral 的模块并加入下面一行代码
Friend DataStuff As DataClass
这一行代码为我的新类 DataClass 创建了一个友元变量使你可以完全访问程序集对这个简单例子来说也就是指完整的应用程序然后我添加了下面的代码到 Form 的 Load 事件
DataStuff = New DataClass
MetxtstDataDataBindingsAdd(Text DataStuff MyData)
MetxtndDataDataBindingsAdd(Text DataStuff MoreData)
第一行建立一个 DataClass 新实例下面两行代码将数据绑定到 textbox 控件对这个窗体而言就这么些操作!
现在你怎样让它们与 Form 和其它窗体上的数据同步呢?将下面两行加入到 Form 的窗体load 事件中去
MetxtstDataDataBindingsAdd(TextDataStuff MyData)
MetxtndDataDataBindingsAdd(TextDataStuff Moredata)
这个方法容易确保所有窗体上的几乎任何类型的数据处于同步状态你可以简单地将控件绑定到某个类的相同实例上这就行了
现在来看另一个方法我创建了一个名为 frmBase 的新窗体这时我在上面放一个 textbox (txtNextData)和 label我想 让应用程序的每个窗体都共享这个 textbox 和 label并且我希望它们互相之间保持同步于是我重建这个工程通过从新的 frmBase 中的继承 我创建了 Form 和Form因此它们继承了所有新的控件但是我怎样能保持这些控件同步呢?这时必须写一点代码去达到此效果这些代码在单个的类中通过简单地调用一个函数而被复用
Figure 中的代码展示了这个称为 modGeneral 模块它的第一个任务是定义两个变量MyForms 和 localNextDataMyForms 是一个 集合它将包含我想要同步的窗体列表localNextData变量将储存所有我想要在窗体里显示的数据注意这些变量可以驻留于某个类中而不是某个模块里
AddForm 过程来自 modGeneral带一个窗体实例参数并将其加入 MyForms 集合中我将在UpdateControlsNextData 过程中使用这个 集合以决定哪些窗体要更新AddForm 也调用UpdateControlsNextData 来确保一个新窗体是用正确的数据更新的
modGeneral 中的其它代码是 NextData 属性这些属性的 set 存取器更新 localNextData 并也调用 UpdateControlsNextData 去同步所有窗体这时所有我需要做的是 在想要改变它时设置 NextData通过调用 UpdateControlsNextData所有窗体将被更新第三个方法是定制链接它是第二个方法的精华版我创建它以获得多一些窗体控件处理的灵活性例如我只想跟蹤和处理某些窗体这些窗体包含必须同步的控件这个方法 还可以让我自己定义拟同步的控件并且只处理这些控件的窗体
我为这个办法添加了另一个模块 (modGeneralv)如 Figure 所示该模块包括一个集合(MyFormsToUpdate)其中包含所有我想要同步的窗体这个模块 还有一个新的数组 (ControlsToUpdate)它提供一个我要同步的控件列表该数组的定义如下
Private ControlsToUpdate() As String = {txtCustomer txtAddress txtName}
这个模块里有一个新的替代 AddForm 的改良版本叫做 AddFormToUpdate该方法工作方式与AddForm 类似但现在它只添加拥有一个或多 个 ControlsToUpdate 数组中控件的窗体因此只有那些含有特定控件的窗体在更新集合中它使我可以从每个窗体中调用该函数如果我决定以后添加某个特定的控件它将会被自动添加到窗体列表我只需对窗体代码做细小的改动便可以实现
这个模块还包含 UpdateControlsOnAllForms 过程它执行更新代替上一个方法中使用的一个应用程序级变量我现在使用主窗体的概念因此我可以将那个窗体的值拷贝到集合中的所有其它窗体UpdateControlsOnAllForms 其实就是一组简单的 ForNexts 循环遍历某个窗体的所有控件找到需要更新的控体并更新它们
为了在我的窗体中实现这一功能我在窗体的 Load 事件中加入了这一行代码 AddFormToUpdate(Me)
另外一种可选的方法我可以将它添加到构造函数这一行代码将把当前窗体实例添加到集合进行更新 现在让我们考察单个事件过程
Private Sub txt_Leave(ByVal sender As Object _
ByVal e As SystemEventArgs) Handles txtAddressLeave _
txtCustomerLeave txtNameLeave
UpdateControlsOnAllForms(Me)
End Sub
这段代码将我想要同步的所有三个控件 (txtAddresstxtCustomer 和 txtName)的 Leave 事件捆绑到一个事件句柄上这时我可以添加一行代码 来调用 UpdateControlsOnAllFormsMe 被传递到该过程调用从而导致其它窗体与该窗体同步
现在我有三个版本的代码它们都可以同步窗体中控件因此我可以进行选择我可能已经使用了自定义事件在 DataClass 中定义某个事件并让每个窗体都预订它 然后当这个事件触发时这些窗体可以从每个事件句柄中获取新的数据并设置适当的控件但是这样做所需的代码量一点也不会比第一种方法中将控件绑定到类来得少我可以构建单个实现更新的过程并将该过程放到某个模块中我需要向该过程传递窗体实例来实现更新我可以用类中的某个事件句柄触发这个过程此过程看起来就像这样
Sub UpdateControls(ByVal ThisForm As frmBase)
With ThisForm
txtNextDataText = localNextData
End With
End Sub
ThisForm 参数被定义为 frmBase 类型以便它可以访问 IntelliSense 并获得窗体的自定义属性简单地将它写成 Form 将无法显示 frmBase 中的属性及其派生窗体
另一选择是使用委托当然委托可以让我将委托调用重定向到每个窗体的方法上如果我使用多播机制那么我可以让每个窗体都处理该事件并更新相应的控件用委托建立这样的功能听起来确实简单但 对我来说它更麻烦且没有实践价值此外与第三个方法中的 ForNext 循环嵌套相比这个代码并不难理解毕竟一个应用程序花费最大的部分仍然是它的维护