元ネタ:[WPF][C#]Model View ViewModelパターンでハローワールド
http://blogs.wankuma.com/kazuki/archive/2009/02/23/168586.aspx
ぼくのVBへの愛が試される瞬間。
誰も書いてくれないんだったら自分で書く。(C#の物まねw)
ということで、かずきさんのブログからパクってきました^^;
本家のC#版と比較して、VBへの愛を深めてくださいorz
■まずは、DelegateのICommandから。いきなりEventでツンツンお姉さん発見
Imports System
Imports System.Windows.Input
Public Class DelegateCommand : Implements ICommand
''' <summary>
''' 実行する処理と、実行可能かどうかの判断を
''' delegateで指定可能なコマンドクラス。
''' </summary>
Private _executeAction As Action(Of Object)
Private _canExecuteAction As Func(Of Object, Boolean)
'そういえばコンストラクタの宣言方法がまったく違いましたねw
Public Sub New(ByVal executeAction As Action(Of Object), _
ByVal canExecuteAction As Func(Of Object, Boolean))
_executeAction = executeAction
_canExecuteAction = canExecuteAction
End Sub
#Region "ICommand の実装"
Public Function CanExecute(ByVal parameter As Object) As _
Boolean Implements System.Windows.Input.ICommand.CanExecute
Return _canExecuteAction(parameter)
End Function
'CommandManagerからイベント発行してもらうようにする。頑張れカスタムイベント
'デフォルトで勝手にイベントを定義してくれる有難迷惑に乾杯^^/ あーーーうざい。さっくりコメントアウト
'Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
'Implements System.Windows.Input.ICommand.CanExecuteChanged
Private _CanExecuteChanged As EventHandler
Public Custom Event CanExecuteChanged As EventHandler _
Implements System.Windows.Input.ICommand.CanExecuteChanged
AddHandler(ByVal value As EventHandler)
Me._CanExecuteChanged = _
CType(System.Delegate.Combine(Me._CanExecuteChanged, value), EventHandler)
AddHandler CommandManager.RequerySuggested, Me._CanExecuteChanged
End AddHandler
RemoveHandler(ByVal value As EventHandler)
Me._CanExecuteChanged = _
CType(System.Delegate.Remove(Me._CanExecuteChanged, value), EventHandler)
RemoveHandler CommandManager.RequerySuggested, Me._CanExecuteChanged
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
If (Not Me._CanExecuteChanged Is Nothing) Then
Me._CanExecuteChanged(sender, e)
End If
End RaiseEvent
End Event
Public Sub Execute(ByVal parameter As Object) _
Implements System.Windows.Input.ICommand.Execute
_executeAction(parameter)
End Sub
#End Region
End Class
■Modelの作成
自動プロパティ裏疾しす
Public Class Person
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
■ViewModelの作成
もうね、ツンツンツンツン、ハイヒールを履き始めましたよんw
Imports System.ComponentModel
Public Class HelloWorldViewModel : Implements INotifyPropertyChanged, IDataErrorInfo
#Region "コンストラクタと、コンストラクタで初期化するフィールド "
Private _model As Person
Public Sub New(ByVal model As Person)
_model = model
End Sub
#End Region
#Region "入力・出力用プロパティ"
' ModelクラスのNameプロパティの値の取得と設定
Public Property Name() As String
Get
Return _model.Name
End Get
Set(ByVal value As String)
If _model.Name = value Then Return
_model.Name = value
OnPropertyChanged("Name")
End Set
End Property
Private _message As String
Public Property Message() As String
Get
Return _message
End Get
Set(ByVal value As String)
'If _message.Equals(value) Then Return
_message = value
OnPropertyChanged("Message")
End Set
End Property
#End Region
#Region "コマンド"
Private _createMessageCommand As ICommand
Public ReadOnly Property CreateMessageCommand() As ICommand
Get
' 作成済みなら、それを返す
If Not IsNothing(_createMessageCommand) Then Return _createMessageCommand
' 遅延初期化
' 今回は、処理が単純なのでラムダ式で全部書いたが、通常は
' ViewModel内の別メソッドとして定義する。
'VBでもラムダ式で...ぼけ、かす、あほ(やばい、VBへの愛が...
'Function式なので、なにがしかの戻り値が必要。んでもって...。
'Me.Message = string.Format("こんにちは{0}さん", Me.Name)
'ラムダ式では、これは代入じゃなくて比較を意味するんですねこのくそボケは(使えんorz)
'心の叫び誰か「てめぇの書き方が間違ってる!!」ってdisってぇ(できればメガネ女子)
_createMessageCommand = New DelegateCommand( _
AddressOf updateMessage, _
Function(param) String.IsNullOrEmpty(CType(Me, IDataErrorInfo)("Name")))
Return _createMessageCommand
End Get
End Property
'諦めてメソッド作りましょうorz
Private Sub updateMessage()
Me.Message = String.Format("こんにちは{0}さん", Me.Name)
End Sub
#End Region
#Region "IDataErrorInfo メンバ"
Public ReadOnly Property [Error]() As String Implements System.ComponentModel.IDataErrorInfo.Error
Get
Return Nothing
End Get
End Property
Default Public ReadOnly Property Item(ByVal columnName As String) As String _
Implements System.ComponentModel.IDataErrorInfo.Item
Get
Try
If columnName = "Name" Then
If String.IsNullOrEmpty(Me.Name) Then
Return "名前を入力してください"
End If
End If
Return Nothing
Finally
CommandManager.InvalidateRequerySuggested()
End Try
End Get
End Property
#End Region
#Region "INotifyPrpertyChangedの実装"
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(ByVal name As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub
#End Region
End Class
■Viewの作成
XAMLもえー。既定の名前空間萌えー
<UserControl x:Class="HelloWorldView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Vertical">
<TextBlock Text="名前:" />
<!--^Nameプロパティのバインド、即座に変更がViewModelに通知されるようにする -->
<TextBox Name="textBoxName"
Text="{Binding Name, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
<!-- あればエラーメッセージを標示する -->
<TextBlock
Text="{Binding ElementName=textBoxName, Path=(Validation.Errors).CurrentItem.ErrorContent}"
Foreground="Red"/>
<Separator />
<Button Content="Create Message" Command="{Binding CreateMessageCommand}" />
<TextBlock Text="{Binding Message}" />
</StackPanel>
</UserControl>
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<ContentPresenter Content="{Binding}" />
</Grid>
</Window>
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:WPFMVVMHelloWorld"
Startup="Application_Startup">
<Application.Resources>
<!-- ViewModelとViewの関連付け -->
<DataTemplate DataType="{x:Type l:HelloWorldViewModel}">
<l:HelloWorldView />
</DataTemplate>
</Application.Resources>
</Application>
<!-- 2010/1/4 .Resourcesが欠落していたので直しました -->
■仕上げ
Application.xaml.vb書いて終わり^^
Imports System.Windows
Class Application
' Startup、Exit、DispatcherUnhandledException などのアプリケーション レベルのイベントは、
' このファイルで処理できます。
'Application_Startup名前が一緒名だけ。Handlesがついてちゃだめだよん。
'ついているとXAMLで定義したものと2回呼ばれる><
Private Sub Application_Startup(ByVal sender As Object, ByVal e As System.Windows.StartupEventArgs)
Dim objWindow = New Window1()
objWindow.DataContext = New HelloWorldViewModel(New Person())
objWindow.Show()
End Sub
End Class
■結論
VBにはVBの書き方があるの。C#の真似しようとしたらVBちゃんスネちゃった...
#ということで、誰かVBで書く方法教えてくれやがれ下さいorz