ロジックコードを記述する
ソリューションエクスプローラ内のMainPage.xamlを展開し、MainPage.xaml.vbをダブルクリックしてコード画面を開きます。
リスト2のようにロジックコードを記述します。
リスト2: ロジックコード(MainPage.xaml.vb)
1 | <!--//--><![CDATA[// ><!-- |
XML to LINQでXMLを処理するクラスの含まれるSystem.Xml.Linq名前空間をインポートします。ファイルの入出力に関するクラスの含まれるSystem.IO名前空間をインポートします。また、エンティティ クラスのメタデータを定義するために使用される属性クラスを提供する、System.ComponentModel.DataAnnotations名前空間をインポートしておきます。
1 | <!--//--><![CDATA[// ><!-- |
5 | Imports System.ComponentModel.DataAnnotations |
PersonalInfoクラス内に、「ID」、「氏名」、「年齢」、「性別」、「住所」、「勤務先」のプロパティを定義しておきます。
1 | <!--//--><![CDATA[// ><!-- |
3 | Public Class PersonalInfo |
「ID」の値を保持するプロパティに対して、RequiredAttribute 属性(必須項目)を適用します。データが不正な場合はErrorMessageが表示されます。
検証する型に関する情報を提供する、ValidationContextの新しいインスタンスmyValidationContextオブジェクト(検証対象オブジェクトで初期化されている)を生成します。
ValidationContextのパラメータは下記の通りです。
- ValidationContext(検証対象オブジェクト,サービスプロバイダー(ここではNothingを指定),検証に関連する値のコレクション(ここではNothingを指定))
検証するメンバのプログラム名をMemberNameプロパティで指定します。ここでは”ID”を指定しています。関連付けられているValidationAttribute 属性の値を検証するValidatorの、ValidatePropertyメソッドで、指定されたプロパティの値が有効であるかどうかを判別します。
01 | <!--//--><![CDATA[// ><!-- |
03 | <Required(ErrorMessage:="IDは必須です。!")> |
04 | Public Property ID() As String |
08 | Set(ByVal value As String) |
09 | If Equals(IDstr, value) Then Return |
10 | Dim myValidationContext As ValidationContext = New ValidationContext(Me, Nothing, Nothing) |
11 | myValidationContext.MemberName = "ID" |
12 | Validator.ValidateProperty(value, myValidationContext) |
「年齢」の値を保持するプロパティに対してRangeAttribute 属性(データが指定された数値の範囲内にあるかどうかを検証)を適用しています。データが不正な場合はErrorMessageが表示されます。検証する型に関する情報を提供する、ValidationContextの新しいインスタンスmyValidationContextオブジェクト(検証対象オブジェクトで初期化されている)を生成します。検証するメンバのプログラム名をMemberNameプロパティで指定します。ここでは”年齢”を指定しています。
関連付けられているValidationAttribute 属性の値を検証するValidatorの、ValidatePropertyメソッドで、指定されたプロパティの値が有効であるかどうかを判別します。
01 | <!--//--><![CDATA[// ><!-- |
03 | <Range(0, 120, ErrorMessage:="年齢の値が不正です。")> |
04 | Public Property 年齢() As String |
08 | Set(ByVal value As String) |
09 | If Equals(ageStr, value) Then Return |
10 | Dim myValidationContext As ValidationContext = New ValidationContext(Me, Nothing, Nothing) |
11 | myValidationContext.MemberName = "年齢" |
12 | Validator.ValidateProperty(value, myValidationContext) |
19 | Property 勤務先 As String |
SexListクラス内でString型の新しいリストであるmySexListを宣言しておきます(A)。
String型のリストである、読み取り専用のsexInfoプロパティを定義します。その中で、mySexListオブジェクトにAddメソッドで「男性」、「女性」の項目を追加しておきます。この追加されたmySexListオブジェクトを戻り値とします。この値が、DataFormの「性別」セルにレイアウトされたComboBoxコントロールに表示されます。
■(A)
01 | <!--//--><![CDATA[// ><!-- |
04 | Dim mySexList As New List(Of String) |
05 | Public ReadOnly Property sexInfo As List(Of String) |
PesonalInfoクラスの新しいリストとして作成するmyPersonalInfoをメンバ変数として宣言します。
1 | <!--//--><![CDATA[// ><!-- |
3 | Dim myPersonalInfo As New List(Of PersonalInfo) |
6 | Dim selectSex As String |
7 | Dim no As Boolean = False |
■ページが読み込まれた時の処理
DataFormにデータをバインドするDataShowプロシジャを実行します。
1 | <!--//--><![CDATA[// ><!-- |
3 | Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded |
■DataFormにデータをバインドする処理
IsRunningOutOfBrowserプロパティでアプリケーションがブラウザ外で実行されているかどうかをチェックし、HasElevatedPermissionsプロパティで、アプリケーションが高い信頼性のあるブラウザ外で動作しているかをチェックします。
ブラウザ外で実行されず、高い信頼性に基づいていない場合は、メッセージボックスを表示します。
ブラウザ外で実行され、高い信頼性に基づいている場合は、以下の処理を実行します。
Path.CombineメソッドでMyDocumentsフォルダのパスと、personalInfo_ID_sex_2.xmlのファイル名を連結し、変数filePathに格納します。MyDocumentsフォルダ内にpersonalInfo_ID_sex_2.xmlというファイルがない場合は、メッセージボックスを表示します。
新しいStreamReaderのインスタンスである、readerオブジェクトを生成します。ReadToEndメソッドでファイルの内容を読み取ります。読み取った内容を変数xmlDataに格納します。StreamReaderを閉じます。StreamReaderクラスは、標準テキストファイルから情報の行を読み込みます。つまり、読み込み可能なファイルは、テキスト形式のファイルに限られます。
XElement.Parseメソッドで、xmlDataに格納されたXML情報を読み取ります。ParseメソッドはXMLを格納した文字列からXElementを読み取ります。読み取ったXML情報から、要素のコレクションを取得するクエリ(query)を定義します。myPersonalInfoオブジェクト内をClearメソッドで一度クリアしておきます。このコードを記述しておかないとデータの追加や編集保存を繰り返しているとエラーが発生する場合があります。
queryを実行します。クエリコレクション内を変数resultで反復処理しながら、以下の処理を実行します。
PersonalInfoクラスのリストとして作成した、myPersonalInfoオブジェクトのAddメソッドで、PersonalInfoクラスの各プロパティ(「ID」、「氏名」、「年齢」、「性別」、「住所」、「勤務先」)に、XML要素(、、、、、)の値を追加します。DataFormコントロールのItemsSourceプロパティにmyPersonalInfoオブジェクトを指定します。DataFormコントロールにXMLデータがバインドされます。
01 | <!--//--><![CDATA[// ><!-- |
04 | If App.Current.IsRunningOutOfBrowser = False And App.Current.HasElevatedPermissions = False Then |
05 | MessageBox.Show("TrustedモードのOut-Of-Browserで実行してください。") |
08 | filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "personalInfo_ID_sex_2.xml") |
09 | Dim reader As StreamReader = New StreamReader(filePath, System.Text.Encoding.GetEncoding("utf-8")) |
10 | Dim xmlData As String = reader.ReadToEnd |
12 | xmldoc = XElement.Parse(xmlData) |
13 | Dim query = From c In xmldoc.Descendants("情報") Select c |
14 | myPersonalInfo.Clear() |
15 | For Each result In query |
17 | .Add(New PersonalInfo With {.ID = result.Element("ID").Value, |
18 | .氏名 = result.Element("氏名").Value, |
19 | .年齢 = result.Element("年齢").Value, |
20 | .性別 = result.Element("性別").Value, |
21 | .住所 = result.Element("住所").Value, |
22 | .勤務先 = result.Element("勤務先").Value}) |
25 | DataForm1.ItemsSource = myPersonalInfo |
■データの新規追加アイコン[+]をクリックしたときの処理
データの修正か、追加保存かを判別するメンバ変数noにTrueを指定します。noがTrueの場合はデータの追加保存を意味します。DataFormのカレントアイテムのインデックを取得する、CurrentItemプロパティに1を指定します。一時的に2ページ目(インデックスは0から開始のため)を選択させます。この処理を記述しておかなければ、新規にデータを追加する[+]アイコンをクリックした際、ツールバーの使用が不可になってしまいます。これを防ぐため、DataFormの2ページ目を一時的に選択させます。
01 | <!--//--><![CDATA[// ><!-- |
03 | Private Sub DataForm1_AddingNewItem(ByVal sender As Object, ByVal e As System.Windows.Controls.DataFormAddingNewItemEventArgs) Handles DataForm1.AddingNewItem |
05 | DataForm1.CurrentIndex = 1 |
06 | AddSave.IsEnabled = True |
07 | EditSave.IsEnabled = False |
■ComboBoxから項目が選択された時の処理
FindNameInContentメソッドで、指定された名前(mySex)を持つComboBoxオブジェクトから、選択された項目をメンバ変数selectSexに格納しておきます。
1 | <!--//--><![CDATA[// ><!-- |
3 | Private Sub ComboBox_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs) |
4 | selectSex = DirectCast(DataForm1.FindNameInContent("mySex"), ComboBox).SelectedItem.ToString |
■[編集保存]ボタンがクリックされた時の処理
メンバ変数noの値がTrue(追加保存の場合)のときに、[編集保存]ボタンがクリックされた場合は、メッセージを表示します。
DataFormのカレントアイテムのインデックスを変数myIndexに格納します。
FindNameInContentメソッドで、指定された名前をもつDataForm内のTextBoxを参照します。「年齢」に入力された値が0より小さく120より大きい場合は警告メッセージを表示します。
変数myIndexに該当する要素の各子要素を参照します。Valueプロパティで、参照した各要素の値に、DataForm内のTextBoxの値を指定します。
「ID」の欄が空白でない場合は、ファイル名と文字コードで初期化された新しいStreamWriterのインスタンスである、writerオブジェクトを生成します。Writeメソッドで、編集修正されたXMLデータ(xmldoc.ToString)をストリームに書き込みます。StreamWriterを閉じます。
01 | <!--//--><![CDATA[// ><!-- |
03 | Private Sub EditSave_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles EditSave.Click |
06 | MessageBox.Show("追加保存ボタンをクリックしてください。") |
10 | Dim myIndex As Integer = DataForm1.CurrentIndex |
11 | Dim IDdata As TextBox = DirectCast(DataForm1.FindNameInContent("myID"), TextBox) |
12 | Dim nameData As TextBox = DirectCast(DataForm1.FindNameInContent("myName"), TextBox) |
13 | Dim ageData As TextBox = DirectCast(DataForm1.FindNameInContent("myAge"), TextBox) |
14 | Dim addressData As TextBox = DirectCast(DataForm1.FindNameInContent("myAddress"), TextBox) |
15 | Dim companyData As TextBox = DirectCast(DataForm1.FindNameInContent("myCompany"), TextBox) |
17 | If CInt(ageData.Text) < 0 OrElse CInt(ageData.Text) > 120 Then |
18 | MessageBox.Show("年齢が不正です。") |
22 | Dim IDQuery = xmldoc.Descendants("情報")(myIndex).<ID> |
23 | IDQuery.Value = IDdata.Text |
24 | Dim nameQuery = xmldoc.Descendants("情報")(myIndex).<氏名> |
25 | nameQuery.Value = nameData.Text |
26 | Dim ageQuery = xmldoc.Descendants("情報")(myIndex).<年齢> |
27 | ageQuery.Value = ageData.Text |
28 | Dim sexQuery = xmldoc.Descendants("情報")(myIndex).<性別> |
29 | sexQuery.Value = selectSex |
30 | Dim addressQuery = xmldoc.Descendants("情報")(myIndex).<住所> |
31 | addressQuery.Value = addressData.Text |
32 | Dim companyQuery = xmldoc.Descendants("情報")(myIndex).<勤務先> |
33 | companyQuery.Value = companyData.Text |
34 | If IDdata.Text <> String.Empty Then |
35 | Dim writer As StreamWriter = New StreamWriter(filePath, False, System.Text.Encoding.GetEncoding("utf-8")) |
37 | writer.Write(xmldoc.ToString) |
39 | MessageBox.Show("修正保存しました。") |
41 | MessageBox.Show("IDは必須です。") |
45 | MessageBox.Show(ex.Message) |
■[追加保存]ボタンがクリックされた時の処理
メンバ変数noの値がFalse(編集保存の場合)のときに、[追加保存]ボタンがクリックされた場合は、メッセージを表示します。
DataFormのカレントアイテムのインデックスを変数myIndexに格納します。
FindNameInContentメソッドで、指定された名前をもつDataForm内のTextBoxを参照します。「ID」が未入力であったり、「年齢」に入力された値が0より小さく120より大きい場合は警告メッセージを表示します。
ファイル名と文字コードで初期化された新しいStreamWriterのインスタンスである、writerオブジェクトを生成します。New XElementコンストラクタで要素を生成し、その子要素として、、、、、要素を生成します。これら子要素の値は参照しておいた、DataForm内の各TextBoxの値です。「性別」の値だけは、ComboBoxから選択された値を保持している変数、selectSexの値になります。Addメソッドで、生成したXMLデータをxmldocオブジェクトに追加します。Writeメソッドで、新規データの追加されたXMLデータ(xmldoc.ToString)をストリームに書き込みます。StreamWriterを閉じます。DataFormに追加したデータをバインドするために、DataShowプロシージャを実行します。
01 | <!--//--><![CDATA[// ><!-- |
03 | Private Sub AddSave_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles AddSave.Click |
06 | MessageBox.Show("編集保存ボタンをクリックしてください。") |
10 | Dim myIndex As Integer = DataForm1.CurrentIndex |
11 | Dim IDdata As TextBox = DirectCast(DataForm1.FindNameInContent("myID"), TextBox) |
12 | Dim nameData As TextBox = DirectCast(DataForm1.FindNameInContent("myName"), TextBox) |
13 | Dim ageData As TextBox = DirectCast(DataForm1.FindNameInContent("myAge"), TextBox) |
14 | Dim addressData As TextBox = DirectCast(DataForm1.FindNameInContent("myAddress"), TextBox) |
15 | Dim companyData As TextBox = DirectCast(DataForm1.FindNameInContent("myCompany"), TextBox) |
17 | If IDdata.Text = String.Empty Then |
18 | MessageBox.Show("IDは必須です。") |
22 | If CInt(ageData.Text) < 0 OrElse CInt(ageData.Text) > 120 Then |
23 | MessageBox.Show("年齢が不正です。") |
27 | Dim writer As StreamWriter = New StreamWriter(filePath, False, System.Text.Encoding.GetEncoding("utf-8")) |
28 | Dim addXml As XElement = New XElement("情報", |
29 | New XElement("ID", IDdata.Text), |
30 | New XElement("氏名", nameData.Text), |
31 | New XElement("年齢", ageData.Text), |
32 | New XElement("性別", selectSex), |
33 | New XElement("住所", addressData.Text), |
34 | New XElement("勤務先", companyData.Text)) |
37 | writer.Write(xmldoc.ToString) |
41 | MessageBox.Show("データが追加保存されました。") |
43 | MessageBox.Show(ex.Message) |
■編集が開始された時に発生するイベント
メンバ変数noの値がTrueのとき、すなわち、追加保存の場合は、[編集保存]ボタンの使用を不可とし、編集時に[編集保存]ボタンの使用を可能にします。
01 | <!--//--><![CDATA[// ><!-- |
03 | Private Sub DataForm1_BeginningEdit(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles DataForm1.BeginningEdit |
05 | EditSave.IsEnabled = False |
07 | EditSave.IsEnabled = True |
■削除アイコン[-]が選択された時の処理
DataFormのカレントアイテムのインデックスを変数myIndexに格納します。FindNameInContentメソッドで、指定された名前(myID)をもつDataForm内のTextBoxを参照します。MessageBox.ShowメソッドでIDに該当するデータを削除するかどうかの確認メッセージ([OK]と[キャンセル]付き)を表示します。
[OK]ボタンをクリックした場合は、ファイル名と文字コードで初期化された新しいStreamWriterのインスタンスwriterオブジェクトを生成します。インデックスに該当する要素を取得します。Removeメソッドで要素とその子要素を削除します。IDに該当する要素の削除されたXMLデータ(xmldoc.ToString)をWriteメソッドでストリームに書き出します。StreamWriterオブジェクトを閉じます。
[キャンセル]の場合は処理を中止します。
01 | <!--//--><![CDATA[// ><!-- |
03 | Private Sub DataForm1_DeletingItem(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles DataForm1.DeletingItem |
04 | Dim myIndex As Integer = DataForm1.CurrentIndex |
05 | Dim IDdata As TextBox = DirectCast(DataForm1.FindNameInContent("myID"), TextBox) |
06 | Dim kakunin = MessageBox.Show(IDdata.Text & "のデータを削除しますか?", "削除確認", MessageBoxButton.OKCancel) |
08 | Case MessageBoxResult.OK |
09 | Dim writer As StreamWriter = New StreamWriter(filePath, False, System.Text.Encoding.GetEncoding("utf-8")) |
10 | Dim delQuery = xmldoc.Descendants("情報")(myIndex) |
13 | writer.Write(xmldoc.ToString) |
15 | Case MessageBoxResult.Cancel |