Livet をカスタマイズする(1.0.6.1版 VB.NET用)

以前のエントリからだいぶ日にちが経ち、Livet も 1.0.6.1 と大きくバージョンアップしました。それに伴い仕様も大きく変わり、VB ユーザーには少々使いづらくなったので、以前の改造だけじゃ足りない部分も増えてます。そこで最新バージョンに合わせ、Livet を改造したいと思います。

プロジェクトテンプレートの変更

1.0以降大きく変わったのが、プロジェクトテンプレートです。テンプレートは、以下のフォルダにある Livet_WPF4.x_VB.zip に含まれてるので、これを編集します。

Visual Studio のインストールフォルダ/Common7/IDE/ProjectTemplatesCache/VisualBasic/Windows/1041

なおテンプレートの本体は

Visual Studio のインストールフォルダ/Common7/IDE/ProjectTemplates/VisualBasic/Windows/1041

にありますが、こちらは通常使いませんのでとりあえず放置しときます。ただし VisualStudio のインストーラーで「修復」を実行すると初期化されてしまうので、時間があればこちらも変更しとくのをお勧めします。

Model・ViewModel・View の各VBにネームスペースが追加されてますが、VB の場合、正直不要なのでばっさり削除。さらに Option ステートメントと Imports を追加します。なお空白行やコメントは記事の都合上割愛してますが、実際のファイルではそのまま残してます。

Model.vb

Option Explicit On
Option Strict On

Imports Livet

Friend Class Model
    Inherits NotificationObject
End Class


ViewModel はもっともよく使うので、Imports を大量に追加。プロジェクトで生成する分には Imports を追加しなくてもいいのですが、私の場合、既存のプロジェクトに後から ViewModel を追加することがあるので、ここで ViewModelのテンプレートの仕様を固めてしまい、項目テンプレートにコピーします。
後 1.0以降から追加されたのが、ViewModel の Dispose。これは使う場面が多いので、テンプレートに雛形を記述しときます。

MainWindowViewModel.vb

Option Explicit On
Option Strict On

Imports System.Collections.ObjectModel
Imports Livet
Imports Livet.Commands
Imports Livet.EventListeners
Imports Livet.Messaging
Imports Livet.Messaging.Windows

Public Class MainWindowViewModel
    Inherits ViewModel

    ' ・・・・・・ 	 
    Public Sub Initialize()
    End Sub

#Region "Dispose Support"
    Protected Overrides Sub Dispose(disposing As Boolean)
        MyBase.Dispose(disposing)
        If (disposing) Then
        End If
    End Sub
#End Region

End Class


View も以下のように変更します。MainWindow.xaml と MainWindow.xaml.vb の二つを編集します。

MainWindow.xaml.vb

Option Explicit On
Option Strict On

Imports Livet

Class MainWindow 
End Class


MainWindow.xaml

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:local="clr-namespace:$safeprojectname$"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <i:Interaction.Triggers>
        <!--WindowのContentRenderedイベントのタイミングでViewModelのInitializeメソッドが呼ばれます-->
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
        </i:EventTrigger>
        <!--Windowが閉じたタイミングでViewModelのDisposeメソッドが呼ばれます-->
        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>
        <!--WindowのCloseキャンセル処理に対応する場合は、WindowCloseCancelBehaviorの使用を検討してください-->
    </i:Interaction.Triggers>
    <Grid>
    </Grid>
</Window>

項目テンプレートを改造

次は項目テンプレートを編集します。項目テンプレートは以下のフォルダにインストールされています。

Visual Studio 2010 のインストールフォルダ/Common7/IDE/ItemTemplatesCache/VisualBasic/WPF/1041

ここに配置されてる ZIP ファイルを展開し編集します。ZIP ファイルと編集するファイルの関係は以下のとおり。メッセージのテンプレートはまだ使い方判ってないので、今回は編集対象から除外しました。

ZIP 編集対象のファイル
LivetModel_VB.zip Model.vb
LivetViewModel_VB.zip ViewModel.vb
LivetWindow_VB.zip Window.xaml
LivetWindow_VB.zip Window.xaml.vb

この四つのファイルを以下のように変更します。

Model.vb

Option Explicit On
Option Strict On

Imports Livet

Friend Class $safeitemname$
    Inherits NotificationObject
    'NotificationObjectはプロパティ変更通知の仕組みを実装したオブジェクトです。
End Class


ViewModel.vb

Option Explicit On
Option Strict On

Imports System.Collections.ObjectModel
Imports Livet
Imports Livet.Commands
Imports Livet.EventListeners
Imports Livet.Messaging
Imports Livet.Messaging.Windows

Public Class $safeitemname$
    Inherits ViewModel

    ' ・・・・・・ 
    Public Sub Initialize()
    End Sub

#Region "Dispose Support"
    Protected Overrides Sub Dispose(disposing As Boolean)
        MyBase.Dispose(disposing)
        If (disposing) Then
        End If
    End Sub
#End Region

End Class


Window.xaml.vb

Option Explicit On
Option Strict On

Imports Livet

Class $safeitemname$

End Class


Window.xaml

<Window x:Class="$safeitemname$"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:local="clr-namespace:$projectrootnamespace$"
        Title="$safeitemname$" Height="350" Width="525">
    <Window.DataContext>
        <local:$safeitemname$ViewModel/>
    </Window.DataContext>
     <i:Interaction.Triggers>
        <!--WindowのContentRenderedイベントのタイミングでViewModelのInitializeメソッドが呼ばれます-->
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
        </i:EventTrigger>
        <!--Windowが閉じたタイミングでViewModelのDisposeメソッドが呼ばれます-->
        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>
        <!--WindowのCloseキャンセル処理に対応する場合は、WindowCloseCancelBehaviorの使用を検討してください-->
    </i:Interaction.Triggers>
    <Grid>
    </Grid>
</Window>

変更通知プロパティのスニペットを改造

Livet をインストールするとスニペット

Visual Studio 2010 のインストールフォルダ/VB(C# ならC#フォルダ)/Snippets/1041/application

に配置されます。VB の場合、Livet用通知プロパティのスニペットは LivetProperty_VB.snippet。これをエディタで開いて、XMLコメントを加えます。ついでにデバッグ時にゲッターをスルーするよう DebuggerNonUserCode 属性を追加。また value の比較ですが、VB の等号演算子では参照型の比較ができないため、Object.Equals を使います。これなら値型はもちろん、文字列や参照型も比較してもらえます。Object.Equals いいね!d(・∀・)グッ!! 後はプロパティの説明や先頭の改行も考慮するとこうなる。
LivetProperty_VB.snippet

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>Livet プロパティ</Title>
      <Author>Livet Project</Author>
      <Description>プロパティを作成します</Description>
      <HelpUrl></HelpUrl>
      <SnippetTypes />
      <Keywords />
      <Shortcut>lprop</Shortcut>
    </Header>
    <Snippet>
      <References />
      <Imports>
        <Import>
          <Namespace>Livet</Namespace>
        </Import>
      </Imports>
      <Declarations>
        <Literal Editable="true">
          <ID>name</ID>
          <Type />
          <ToolTip>プロパティ名</ToolTip>
          <Default>MyProperty</Default>
          <Function />
        </Literal>
        <Literal Editable="true">
          <ID>type</ID>
          <Type />
          <ToolTip>プロパティの型</ToolTip>
          <Default>String</Default>
          <Function />
        </Literal>
        <Literal Editable="true">
          <ID>summary</ID>
          <Type />
          <ToolTip>プロパティの説明</ToolTip>
          <Default>MySummary</Default>
          <Function />
        </Literal>
      </Declarations>
      <Code Language="VB" Kind="" Delimiter="$">
        <![CDATA[#Region "$name$変更通知プロパティ"
Private _$name$ As $type$

''' <summary>
''' $summary$を取得・設定します。
''' </summary>
Public Property $name$() As $type$
    <DebuggerNonUserCode()>
    Get
        Return _$name$
    End Get
    Set(ByVal value As $type$)
        If (Object.Equals(_$name$, value)) Then Return
        _$name$ = value
        RaisePropertyChanged("$name$")
    End Set
End Property
#End Region
]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

ViewModelCommand のスニペット改造

あと ViewModelCommand ですが、これの CenExecute 用ファンクション。スニペットでは戻り値がないためビルドエラーになります。そこで前のエントリと同じく Return True を追加しておきます。ファイルは「LivetViewModelCommand_VB.snippet」です。これをエディタで開き、編集したのち保存します。

LivetViewModelCommand_VB.snippet

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>Livet ViewModelCommand</Title>
      <Author>Livet Project</Author>
      <Description>ViewModelCommandを作成します</Description>
      <HelpUrl></HelpUrl>
      <SnippetTypes />
      <Keywords />
      <Shortcut>lvcom</Shortcut>
    </Header>
    <Snippet>
      <References />
      <Imports>
        <Import>
          <Namespace>Livet.Commands</Namespace>
        </Import>
      </Imports>
      <Declarations>
        <Literal Editable="true">
          <ID>name</ID>
          <Type />
          <ToolTip>コマンド名</ToolTip>
          <Default>MyCommand</Default>
          <Function />
        </Literal>
      </Declarations>
      <Code Language="VB" Kind="" Delimiter="$"><![CDATA[#Region "$name$Command"
    Private _$name$Command As ViewModelCommand

    Public ReadOnly Property $name$Command() As ViewModelCommand
        Get
            If _$name$Command Is Nothing Then
                _$name$Command = New ViewModelCommand(AddressOf $name$, AddressOf Can$name$)
            End If
            Return _$name$Command
        End Get
    End Property

    Private Function Can$name$() As Boolean
        Return True
    End Function

    Private Sub $name$()
        
    End Sub
#End Region
]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

他にも LivetListenerCommand_VB.snippet 等のスニペットが提供されてますが、自分の使いやすいように改造しとくといいと思います。


#2014/05/19 追加 : ViewModel のImports に System.Collections.ObjectModel を追加。
#2014/05/22 追記 : テンプレートキャッシュフォルダ内のファイルはVisualStudioのインストーラーで「修復」を実行すると初期化されてしまうので、テンプレートフォルダ内のファイルも同じ内容で修正しておくことをお勧めします。