实现viewmodel以反映基本模型?

时间:2011-07-04 23:52:13

标签: .net wpf vb.net mvvm .net-4.0

现在用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等。我应该如何处理基本模型查看模型?

谢谢, 亚历克斯。

2 个答案:

答案 0 :(得分:2)

这真的取决于。

如果你的模型已经实现了INotifyPropertyChanged并使用了实现INotifyCollectionChanged的集合类型,我个人觉得直接封装和绑定到XAML中的“Source.Name”有一些真正的优点 - 主要是,它显着减少了代码量,并且(更重要的是)减少了不必要的代码重复量。

但是,Model类通常不是专门针对WPF或Silverlight支持而设计的,并且需要包装。只要您必须将模型的一部分包装到ViewModel中以处理特定通知,包装整个模型就会带来更高的一致性。

这确实需要考虑成本效益权衡。如果您正在与不同的设计师合作,那么包装所有内容将导致API(设计人员使用)的一致性,这有助于减少错误(以您的部分额外重复为代价)。如果你正在做所有事情,那么最重要的是你最有意义的事情。

答案 1 :(得分:-1)

您是希望编写更多VB代码还是稍微长一点的绑定到Source.Name的XAML?