现在用WPF MVVM让我困惑一段时间的东西是例如,当我有一个只包含一些属性和一些验证代码的基础模型时,我然后围绕这个基础模型构建一个视图模型,应该怎么做?视图模型的结构。
例如:
基本型号 - >
Imports ModellingHelper
Imports FTNHelper
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Public Class Parser
Inherits BaseModel
<Required(ErrorMessage:="Name is required.")>
Public Property Name As String
Get
Return GetValue(Function() Name)
End Get
Set(value As String)
SetValue(Function() Name, value)
End Set
End Property
<Required(ErrorMessage:="Description is required.")>
Public Property Description As String
Get
Return GetValue(Function() Description)
End Get
Set(value As String)
SetValue(Function() Description, value)
End Set
End Property
Public Property InputHeaderInfo As InputHeader
Get
Return GetValue(Function() InputHeaderInfo)
End Get
Set(value As InputHeader)
SetValue(Function() InputHeaderInfo, value)
End Set
End Property
Public Property InputVariables As ObservableList(Of Variable)
Get
Return GetValue(Function() InputVariables)
End Get
Set(value As ObservableList(Of Variable))
SetValue(Function() InputVariables, value)
End Set
End Property
Public Property OutputVariables As ObservableList(Of Variable)
Get
Return GetValue(Function() OutputVariables)
End Get
Set(value As ObservableList(Of Variable))
SetValue(Function() OutputVariables, value)
End Set
End Property
Public Sub New()
Name = "New Parser"
Description = "This is a new parser."
InputHeaderInfo = New InputHeader()
InputVariables = New ObservableList(Of Variable)
OutputVariables = New ObservableList(Of Variable)
End Sub
End Class
ViewModel - &gt;
Imports WinTransform.DataModel
Imports System.IO
Imports WPFHelper
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Imports ModellingHelper
Imports Omu.ValueInjecter
Namespace ViewModels
Public Class ParserViewModel
Inherits ViewBase
#Region "Properties"
Public Property Source As Parser
Get
Return GetValue(Function() Source)
End Get
Set(value As Parser)
SetValue(Function() Source, value)
End Set
End Property
Public Property InputFile As FileInfo
Get
Return GetValue(Function() InputFile)
End Get
Set(value As FileInfo)
SetValue(Function() InputFile, value)
NotifyPropertyChanged(Function() InputFileContents)
NotifyPropertyChanged(Function() InputFileParseLine)
NotifyPropertyChanged(Function() TabVisability)
End Set
End Property
Public ReadOnly Property InputFileContents As String
Get
If Not InputFile Is Nothing Then
Dim mReader = InputFile.OpenText()
Try
Return mReader.ReadToEnd()
Catch ex As Exception
MessageBox.Show(String.Format("Failed to load transform file contents: {0}", ex.Message))
Finally
mReader.Close()
End Try
End If
Return String.Empty
End Get
End Property
Public ReadOnly Property InputFileParseLine As String
Get
If Not InputFile Is Nothing Then
Dim mReader = InputFile.OpenText()
Try
Dim mLines = mReader.ReadToEnd().Split(vbNewLine).Select(Function(l As String) l.Trim())
Dim mLineNo = Source.InputHeaderInfo.TitleLinesFixed + Source.InputHeaderInfo.TitleLinesSkipped + Source.InputHeaderInfo.ColumnHeaderLines + Source.InputHeaderInfo.LinesFixed + Source.InputHeaderInfo.LinesSkipped
If mLineNo >= 0 And mLineNo < mLines.Count() Then
Return mLines(mLineNo)
End If
Catch ex As Exception
MessageBox.Show(String.Format("Failed to load transform file contents: {0}", ex.Message))
Finally
mReader.Close()
End Try
End If
Return String.Empty
End Get
End Property
Public ReadOnly Property TabVisability As Visibility
Get
If Not InputFile Is Nothing Then
Return Visibility.Visible
End If
Return Visibility.Hidden
End Get
End Property
Public ReadOnly Property InputVariablesViews As ObservableList(Of VariableViewModel)
Get
Dim mVars As New ObservableList(Of VariableViewModel)
For Each mVar In Source.InputVariables
mVars.Add(New VariableViewModel(mVar))
Next
AddHandler mVars.CollectionChanged, Sub() Source.InputVariables.RefreshList(mVars.Select(Function(v As VariableViewModel) v.Source))
Return mVars
End Get
End Property
Public ReadOnly Property OutputVariablesViews As ObservableList(Of VariableViewModel)
Get
Dim mVars As New ObservableList(Of VariableViewModel)
For Each mVar In Source.OutputVariables
mVars.Add(New VariableViewModel(mVar))
Next
AddHandler mVars.CollectionChanged, Sub() Source.OutputVariables.RefreshList(mVars.Select(Function(v As VariableViewModel) v.Source))
Return mVars
End Get
End Property
Public Property IsSaved As Boolean
Get
If String.IsNullOrEmpty(SaveFile) Then
Return False
End If
If Not IsValid Then
Return False
End If
Return GetValue(Function() IsSaved)
End Get
Set(value As Boolean)
SetValue(Function() IsSaved, value)
End Set
End Property
Public Property SaveFile As String
Get
Return GetValue(Function() SaveFile)
End Get
Set(value As String)
SetValue(Function() SaveFile, value)
End Set
End Property
#End Region
#Region "Commands"
Public ReadOnly Property SelectInputFile As ICommand
Get
Return New RelayCommand(Sub() SelectInputFileExecute())
End Get
End Property
Private Sub SelectInputFileExecute()
Dim mOpenDialog = OpenDialog
If mOpenDialog.ShowDialog() Then
InputFile = New FileInfo(mOpenDialog.FileName)
End If
End Sub
#End Region
Public Sub New()
Source = New Parser()
Init()
End Sub
Public Sub New(ByVal mFileInfo As FileInfo)
Source = LoadParser(mFileInfo)
SaveFile = mFileInfo.FullName
Init()
End Sub
Public Sub Init()
AddHandler PropertyChanged, Sub() IsSaved = False
AddHandler Source.InputHeaderInfo.PropertyChanged, Sub() NotifyPropertyChanged(Function() InputFileParseLine)
End Sub
Public Shared Function LoadParser(ByVal mFileInfo As FileInfo) As Parser
Try
Dim xmlParser As New XmlDataModel.Parser()
xmlParser.FromXmlFile(mFileInfo.FullName)
Dim baseParser As New Parser()
baseParser.InjectFrom(New ParserInjectionXml(baseParser, xmlParser), xmlParser)
Return baseParser
Catch ex As Exception
MessageBox.Show(String.Format("Could not open parser: {0}", ex.Message))
Return New Parser()
End Try
End Function
Public Sub Save()
If String.IsNullOrEmpty(SaveFile) Then
Dim mSaveDialog = SaveDialog
If mSaveDialog.ShowDialog() Then
SaveFile = mSaveDialog.FileName
Else
Return
End If
End If
IsSaved = Save(SaveFile)
End Sub
Public Function Save(ByVal mFilePath As String) As Boolean
SaveFile = mFilePath
Return SaveParser(mFilePath, Source)
End Function
Public Shared Function SaveParser(ByVal mFilePath As String, ByVal mParser As Parser) As Boolean
If Not mParser.IsValid Then
Return False
End If
Try
Dim xmlParser As New XmlDataModel.Parser()
xmlParser.InjectFrom(New ParserInjectionXml(mParser, xmlParser), mParser)
xmlParser.ToXmlFile(mFilePath)
Return True
Catch ex As Exception
MessageBox.Show(String.Format("Could not save parser: {0}", ex.Message))
Return False
End Try
End Function
End Class
End Namespace
我想知道的是,如果有更好的方法来构建视图模型以改进数据绑定,那么我不必绑定到Source.Name
等。我应该如何处理基本模型查看模型?
谢谢, 亚历克斯。
答案 0 :(得分:2)
这真的取决于。
如果你的模型已经实现了INotifyPropertyChanged
并使用了实现INotifyCollectionChanged
的集合类型,我个人觉得直接封装和绑定到XAML中的“Source.Name”有一些真正的优点 - 主要是,它显着减少了代码量,并且(更重要的是)减少了不必要的代码重复量。
但是,Model类通常不是专门针对WPF或Silverlight支持而设计的,并且需要包装。只要您必须将模型的一部分包装到ViewModel中以处理特定通知,包装整个模型就会带来更高的一致性。
这确实需要考虑成本效益权衡。如果您正在与不同的设计师合作,那么包装所有内容将导致API(设计人员使用)的一致性,这有助于减少错误(以您的部分额外重复为代价)。如果你正在做所有事情,那么最重要的是你最有意义的事情。
答案 1 :(得分:-1)
您是希望编写更多VB代码还是稍微长一点的绑定到Source.Name的XAML?