Реализация модели представления для отражения базовой модели? - PullRequest
5 голосов
/ 05 июля 2011

Что-то, что меня некоторое время путало с 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 ->

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 ]

2 голосов
/ 05 июля 2011

Это действительно зависит.

Если ваша Модель уже реализует INotifyPropertyChanged и использует типы коллекций, которые реализуют INotifyCollectionChanged, я лично чувствую, что непосредственная инкапсуляция и привязка к «Source.Name» в XAML имеет некоторые реальныепреимущества - главным образом, это значительно уменьшает объем кода и (что более важно) уменьшает количество ненужного дублирования кода.

Однако классы Model часто не разрабатываются специально с учетом поддержки WPF или Silverlight,и требуют упаковки.Как только вам нужно обернуть части модели в ViewModel для обработки определенных уведомлений, обертывание всей модели приводит к большей согласованности.

Это действительно имеет компромисс между затратами и выгодой.Если вы работаете с другим дизайнером, оборачивание всего приводит к согласованности API (который использует дизайнер), что может помочь уменьшить количество ошибок (за счет некоторого дополнительного дублирования с вашей стороны).Если вы все делаете, то это действительно зависит от вас.

0 голосов
/ 05 июля 2011

Вы бы предпочли написать больше кода VB или иметь более длинный XAML, который связывает вас с Source.Name?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...