控制WPF应用程序中的事件驱动导航

时间:2011-11-11 20:28:07

标签: c# wpf event-handling

我认为这个问题的标题可能是错误的,但我不确定如何用它来表达。我有一个C#4.0(VS2010)WPF应用程序。

此应用程序包含一个带有标题的窗口,其中包含基本信息(徽标,标题等)和一组导航按钮(后退,重试,下一步等)。窗口的其余部分由一个列表框组成,该列表框根据应用程序当前所处的模式填充一个或多个用户控件。

清除模式更改列表框时当前编写代码的方式,添加所有新用户控件,并将按钮设置为其所需状态。这对于每个窗口模式的初始状态都很好,但是当控制内容发生变化时,我无法确定更新导航按钮的好方法。

例如,一个屏幕是配置屏幕,列表框中包含三个用户控件。这些控件是从UserControl继承的自定义类。此外,他们实现了一个定义方法'bool Validate'的接口,该方法确定控件是否已完全填写。

这种情况可能适用于许多其他情况,但这是一个非常简单易懂的通用用例。当屏幕最初加载“下一步”按钮时,其可见性由父窗口控制,可见但禁用,因为子控件可能无效。在某些时候,当用户填写一个或多个控件中的任意数据时,如果调用其Validate方法,则每个控件都会返回true。

在所有控件都有效的位置,下一个按钮将变为启用状态。相当简单的设计。

问题是每个控件都不知道它在哪个屏幕上,这是设计的。我不希望控件必须彼此了解并更新父窗口中的按钮状态。我也不希望父窗口运行轮询线程来每秒调用验证,因为在某些情况下验证可能很复杂。

我认为UserControl中的每个控件的更改事件(文本框,单选按钮等)都会将触发器调用为私有验证事件,这会在接口或类上设置一些公共属性。

f我能做到这一点,父窗口是否有办法以事件驱动的方式响应该属性的更改?我不打算在WPF中这样做,在C#代码中这样做是可取的,因为我还不想进入WPF的复杂性。除了常规轮询之外,我只是不确定如何判断每个控件的'IsValid'属性是否会将所有内容同步为'true',如果这是一个很好的方法。


修改

好的,这是提出问题的另一种方式。我有一个列表(在这种情况下是一个接口列表),并希望能够响应列表中每个项目的公共属性更改,以便我可以在所有项目都采取行动(在这种情况下为bool)真正。以上解释了用例,但这是一个更通用的问题版本。


修改

@Vincent“您可以使用自定义”ValidatedChanged()“事件以更简单的方式执行此操作,您可以以相同的方式挂钩。”

事实证明,这正是我所寻找的。对于数据绑定控件的易用性,属性通知方法似乎更多。我在这个网站上阅读了很多关于如何实现它的帖子,但它确实不是我想要的。我只是希望我的对象通知发生了一个事件,这恰好是一个属性更改,但这不是重点。我找到了在界面中实现事件的文档,我现在正在使用它。感谢您指出我正确的方向,并帮助我意识到我需要的是什么。

1 个答案:

答案 0 :(得分:1)

所以你有一个包含所有控件的ListBox,并且当所有控件都被验证时,应该启用Next按钮? 如果是这样,当你的一个控件验证时,你可以搜索ListBox的所有儿子来检查它们的验证,使用VisualTreeHelper.GetChildren来获取它们。 如果您不希望/不能在ListView上拥有句柄,您可以通过从刚刚验证的控件开始搜索可视树来找到它。 每个控件的每个'Validated'事件都将由'CheckIfAllValidated'事件处理程序处理,并且当所有控件都被验证时,您可以引发一个'AllValidated'事件,该事件将由按钮(以及可能还有一些其他控件)处理启用它。

编辑:我知道您不希望每个组件都知道他们的孩子,但请注意,即使是非常常见的PropertyChanged事件也有一个“发件人”字段,告诉谁提升了该事件。因此,任何PropertyChanged的监听器,例如'validated'属性,都可以上到可视树,当遇到ListView时停止,然后在楼下搜索是否所有具有验证属性的控件都将此属性设置为true。

编辑2: 要更清楚如何操作,可以在窗口新建或窗口加载事件中  或者也许在ContentRendered事件上,取决于控件的加载方式,您 可能会使用该代码将处理程序挂钩到所有控件:

For Each ThisControl In MainListView. 
   Dim ThisControlType = ThisControl.GetType
   Dim ThisControlPropertyChangedEvent = ThisControlType.GetEvent("PropertyChanged")
   ' you might wanna check here if event is not null / nothing
   ThisControlPropertyChangedEvent.AddEventHandler(ThisControl, New PropertyChangedEventHandler(AddressOf APropChanged))
 Next

并以某种方式编写APropChanged:

Public Sub APropChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
If e.PropertyName = "Validated" Then
    Dim ValidatedForAll = True
    For Each ThisControl In MainListView.Items
        Dim ThisControlType = ThisControl.GetType
        Dim ThisControlValidatedProperty = ThisControlType.GetProperty("Validated")
        'you might wanna check for non null here
        If Not ThisControlValidatedProperty.GetValue(ThisControl, Nothing) Then
           ValidatedForAll = False
           Exit For
        End If
    Next
    If ValidatedForAll Then
       MessageBox.Show("Yeeppee")    ' you might send an event instead.
    End If
End If
End Sub

编辑3:您可以使用自定义“ValidatedChanged()”事件以更简单的方式执行此操作,您可以以相同的方式挂钩。