我有一个包含项目列表的视图,TextBox
和保存按钮。 TextBox
绑定到列表中当前所选项的属性。列表的DataSource
绑定到ViewModel中的ObservableCollection<T>
现在,当用户选择列表中的另一个项目并且尚未将其更改保存到TextBox
时,应该询问他是否要放弃他所做的更改。列表中的所选项目只有在回答“是”时才会更改
我遇到的问题是:
我需要在ViewModel中实现对更改的检查,但是我不知道ViewModel何时没有收到通知,所选项目的更改时间。
我提出了以下方法,但它看起来并不干净:
列表中有一个事件SelectedItemsChanging
。我可以使用EventToCommand
行为并将CancelEventArgs
作为参数传递给命令。在命令中,我检查项目是否已更改,如果是,我可以使用messenger发送View侦听的消息。然后,View将向用户显示确认对话框,并将结果返回给ViewModel 以某种方式。如果用户不想丢弃他的更改,ViewModel会将事件args的Cancel
属性设置为true
。
这看起来并不干净,因为它将这个简单的功能分开并将其涂抹在三个文件上,这使得它很难理解。
对于这样的场景,是否有最佳实践?
答案 0 :(得分:1)
我会对模型类进行Dirty检查。示例如下:
Public m_dirtyFields As New Dictionary(Of String, String)
Private Sub AddDirtyField(ByVal ColName As String, ByVal OrigValue As String)
If Not m_dirtyFields.ContainsKey(ColName) Then
m_dirtyFields.Add(ColName, OrigValue)
OnPropertyChanged("IsDirty")
End If
End Sub
Private Sub RemoveDirtyField(ByVal ColName As String)
If m_dirtyFields.ContainsKey(ColName) Then
m_dirtyFields.Remove(ColName)
End If
OnPropertyChanged("IsDirty")
End Sub
Private Sub OnAddress1Changing(ByVal value As String)
If Not m_dirtyFields.ContainsKey("Address1") Then
AddDirtyField("Address1", Address1)
Else
If m_dirtyFields("Address1") = value Then RemoveDirtyField("Address1")
End If
End Sub
Public ReadOnly Property IsDirty
Get
If _Initialized = False Then
m_dirtyFields.Clear()
_Initialized = True
End If
If m_dirtyFields.Count > 0 Then
Return True
Else : Return False
End If
End Get
End Property
上面的示例检查属性值,根据原始值的相似性将它们添加到字典中,并根据字典中的项返回Dirty。
在ViewModel中,您只需检查MyObject.IsDirty,如果它已更改,则弹出一个消息框,要求用户保存(或不保存)。
此外,您可以在记录脏时禁用列表框(因此用户无法更改记录),但在ViewModel上有一个属性,该属性通告了SelectedItem的Dirty属性。
答案 1 :(得分:0)
经过一些研究,我偶然发现了PRISM使用的“交互请求”“模式”。这基本上和我在答案中已经列出的解决方案相同,只是稍微复杂一点。这就是我现在正在使用的。
它的工作原理如下:
IInteractionRequest<TInteractionData>
的属性。此界面仅包含事件Raised
。在视图中,行为绑定到此属性。
<i:Interaction.Behaviors>
<Interaction:NotificationMessageBoxBehavior
SourceObject="{Binding NotificationRequest}" />
</i:Interaction.Behaviors>
绑定行为(在示例中为NotificationMessageBoxBehavior
)控制交互请求的处理方式。例如,在Windows应用程序中,这只是调用MessageBox.Show
,但可能有一个在Silverlight应用程序中有效的替代实现。
这些行为都源自一个公共基类,该基类派生自Behavior<FrameworkElement>
,并具有类型为SourceObject
的依赖项属性IInteractionRequest<TInteractionData>
。这就是行为和交互请求汇集在一起的方式:行为订阅Raised
的{{1}}事件,并在事件发生时执行交互请求。
请求中使用的交互数据的具体实现可以包含在请求完成后调用的回调。此回调可以有一个参数。像这样,交互请求的结果可以流回ViewModel。
答案 2 :(得分:0)
在MVVM for Windows 8中,您可以覆盖PageModel.OnNavigating方法。 http://w8mvvm.codeplex.com/wikipage?title=HandlePageNavigation&referringTitle=Documentation
http://visualstudiogallery.msdn.microsoft.com/b287f569-7bf9-40d2-80f3-02c9945f1f33