Программирование для карманных компьютеров
Шрифт:
18. Теперь можно создать процедуру обработчика события загрузки формы, код которой приведен в листинге 6.7. Листинг 6.7
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
\'Если файл с данными отсутствует в текущем каталоге, мы его создаем, для
\'этого сначала получаем полный путь каталога, в котором расположена
\'программа, в строковую переменную dirStr
dirStr = IO.Path.GetDirectoryName_
(Reflection.Assembly.GetExecutingAssembly.GetName.CodeBase.ToString)
\'Проверяем, есть ли файл c заданным именем по полученному пути
If Not System.IO.File.Exists(dirStr + «\2005.xml») Then
\'Если файла нет – создаем его
\'Создаем экземпляр XmlDocument
Dim myxmlDoc As New Xml.XmlDocument
\'Создаем корневой тег и добавляем его к документу
Dim oROOT As Xml.XmlElement = myxmlDoc.CreateElement(«Y2005»)
myxmlDoc.AppendChild(oROOT)
\'Получаем текущую дату в переменную myDate
Dim myDate As Date = Date.Now
myDate = DateAdd(DateInterval.Day, – 1, myDate)
\'Заполняем файл тегами Data от сегодняшнего дня до конца текущего года
While Not myDate.ToShortDateString = «31.12.2005»
myDate = DateAdd(DateInterval.Day, 1, myDate)
Dim oData As Xml.XmlElement = myxmlDoc.CreateElement(«Data»)
oROOT.AppendChild(oData)
Dim oValue As Xml.XmlAttribute = _ myxmlDoc.CreateAttribute(«value»)
Dim oIndex As Xml.XmlAttribute = _ myxmlDoc.CreateAttribute(«Cnt»)
oValue.InnerText = myDate.ToShortDateString
oIndex.InnerText = «-1»
oData.SetAttributeNode(oValue)
oData.SetAttributeNode(oIndex)
End While
\'Создаем
Dim myPI As Xml.XmlProcessingInstruction = _
myxmlDoc.CreateProcessingInstruction_
(«xml», "version= 1.0 encoding=\'windows-1251 ")
myxmlDoc.InsertBefore(myPI, myxmlDoc.ChildNodes(0))
\'Сохраняем созданный документ
myxmlDoc.Save(dirStr + «\2005.xml»)
End If
\'Если файл со списком категорий отсутствует в текущем каталоге, мы его
\'создаем с пятью категориями Work1, Work2, Work3, Misc, Trash
If Not System.IO.File.Exists(dirStr + «\Category.xml») Then
If Not System.IO.File.Exists(dirStr + «\Category.xml») Then
Dim myxmlDoc As New Xml.XmlDocument
Dim oROOT As Xml.XmlElement = myxmlDoc.CreateElement(«Categoty»)
myxmlDoc.AppendChild(oROOT)
Dim oWork1 As Xml.XmlElement = myxmlDoc.CreateElement(«Work1»)
oROOT.AppendChild(oWork1)
Dim oWork2 As Xml.XmlElement = myxmlDoc.CreateElement(«Work2»)
oROOT.AppendChild(oWork2)
Dim oWork3 As Xml.XmlElement = myxmlDoc.CreateElement(«Work3»)
oROOT.AppendChild(oWork3)
Dim oMisc As Xml.XmlElement = myxmlDoc.CreateElement(«Misc»)
oROOT.AppendChild(oMisc)
Dim oTrash As Xml.XmlElement = myxmlDoc.CreateElement(«Trash»)
oROOT.AppendChild(oTrash)
Dim myPI As Xml.XmlProcessingInstruction = _
myxmlDoc.CreateProcessingInstruction_
(«xml», "version= 1.0 encoding=\'windows-1251 ")
myxmlDoc.InsertBefore(myPI, myxmlDoc.ChildNodes(0))
myxmlDoc.Save(dirStr + «\Category.xml»)
End If
D = DateTime.Now
Label1.Text = System.DateTime.Today.ToShortDateString
\'Вызываем процедуру загрузки данных в ListView
Data_Load(System.DateTime.Today.ToShortDateString)
End SubЧтобы создать и сохранить новый XML-документ, мы воспользовались классом XMLDocument, который позволяет представить существующий XML-документ в виде объекта с набором полей и методов для манипуляции этими полями. Он позволяет создавать и удалять элементы XML как по имени, так и по индексу, осуществлять поиск нужного элемента, заменять или дублировать элементы, сохранять измененный документ. Единственным недостатком этого класса является то, что документ полностью загружается в создаваемый объект. Поскольку на Pocket PC и файловая система, и оперативная память программы физически являются одним и тем же устройством, то просто происходит дублирование информации на время работы с документом.
19. Процедура загрузки данных для текущего дня в компонент ListView приведена в листинге 6.8.
Листинг 6.8Private Sub Data_Load(ByVal MyDate As String)
\'Открываем файл, для это сначала получаем полный путь каталога,
\'в котором расположена программа в строковую переменную dirStr
dirStr = IO.Path.GetDirectoryName_
(Reflection.Assembly.GetExecutingAssembly.GetName.CodeBase.ToString)
\'Создаем экземпляр объекта XmlTextReader
Dim xmlrdrMy As New Xml.XmlTextReader(dirStr + «\2005.xml»)
Dim MyCount, MyIndex As Integer
Dim lvItem As ListViewItem
\'Не реагируем на пробелы и управляющие символы
xmlrdrMy.WhitespaceHandling = xmlrdrMy.WhitespaceHandling.None
\'Переходим к содержимому, пропуская заголовочную часть
xmlrdrMy.MoveToContent
\'В цикле считываем значения из файла, добавляем новую строку в ListView
\'для каждого тега Index и копируем значения атрибутов тега Index в
\'соответствующие поля записи ListView
ListView1.Items.Clear
ListView1.Refresh
While Not xmlrdrMy.EOF
If xmlrdrMy.Name = «Data» Then
If xmlrdrMy.GetAttribute(«value») = MyDate Then
MyIndex = CInt(xmlrdrMy.GetAttribute(«Cnt»))
For MyCount = 0 To MyIndex – 1
xmlrdrMy.Read
lvItem = New ListViewItem(xmlrdrMy.GetAttribute(«Category»))
ListView1.Items.Add(lvItem)
ListView1.Items.Item(MyCount). SubItems.Add_
(xmlrdrMy.GetAttribute(«StartOf»))
ListView1.Items.Item(MyCount). SubItems.Add(xmlrdrMy.GetAttribute(«EndOf»))
ListView1.Items.Item(MyCount). SubItems.Add(xmlrdrMy.GetAttribute(«Note»))
Next
End If
End If
\'Считываем следующий элемент из файла XML
xmlrdrMy.Read
End While
\'Закрываем файл
xmlrdrMy.Close
End SubВ этом случае мы воспользовались классом XmlTextReader для считывания информации из файла. Класс XmlTextReader также позволяет разбирать содержимое XML-документа, но он не создает копию файла в памяти, а считывает его в один проход элемент за элементом. Переход к следующему элементу осуществляется вызовом метода Read.
20. Теперь нужно создать процедуру сохранения данных текущего дня в файл. Эта процедура должна запускаться при переходе от одной даты к другой, а также в момент закрытия приложения. Ее код приведен в листинге 6.9.
Листинг 6.9Private Sub Data_Save(ByVal MyDate As String)
Dim MyCount, MyIndex As Integer
\'Создаем объект XmlDocument
Dim myxml As New Xml.XmlDocument
dirStr = IO.Path.GetDirectoryName_
(Reflection.Assembly.GetExecutingAssembly.GetName.CodeBase.ToString)
\'Загружаем файл в объект XmlDocument
myxml.Load(dirStr + «\2005.xml»)
\'Перебираем все узлы уровня Data и находим сохраняемую дату
For MyCount = 0 To myxml.ChildNodes(1). ChildNodes.Count – 1
If myxml.ChildNodes(1). ChildNodes(MyCount). Attributes(0). InnerText = MyDate Then
\'Удаляем все содержимое этого узла
myxml.ChildNodes(1). ChildNodes(MyCount). RemoveAll
\'И заполняем его текущим содержимым полей ListView. При этом мы создаем
\'заново атрибуты узла Data и узлы Index со всеми атрибутами для каждой
\'строки ListView
\'Создаем атрибут value для текущего узла Data
Dim myValue As Xml.XmlAttribute = myxml.CreateAttribute(«value»)
\'Присваиваем атрибуту value значение текущей даты
myValue.InnerText = MyDate
\'Добавляем атрибут value к текущему узлу Data
myxml.ChildNodes(1). ChildNodes(MyCount). Attributes.Append(myValue)
\'Проделываем предыдущие операции с атрибутом Cnt
Dim mIndex As Xml.XmlAttribute = myxml.CreateAttribute(«Cnt»)
mIndex.InnerText = ListView1.Items.Count
myxml.ChildNodes(1). ChildNodes(MyCount). Attributes.Append(mIndex)
\'Заполняем узел Data вложенными элементами Index
For MyIndex = 0 To ListView1.Items.Count – 1
Dim oIndex As Xml.XmlElement = myxml.CreateElement(«index»)
myxml.ChildNodes(1). ChildNodes(MyCount). AppendChild(oIndex)
Dim oCategory As Xml.XmlAttribute = myxml.CreateAttribute(«Category»)
oCategory.InnerText = ListView1.Items(MyIndex). SubItems(0). Text
myxml.ChildNodes(1). ChildNodes(MyCount). ChildNodes_
(MyIndex). Attributes.Append(oCategory)
Dim oStartOf As Xml.XmlAttribute = myxml.CreateAttribute(«StartOf»)
oStartOf.InnerText = ListView1.Items(MyIndex). SubItems(1). Text
myxml.ChildNodes(1). ChildNodes(MyCount). ChildNodes_
(MyIndex). Attributes.Append(oStartOf)
Dim oEndOf As Xml.XmlAttribute = myxml.CreateAttribute(«EndOf»)
oEndOf.InnerText = ListView1.Items(MyIndex). SubItems(2). Text
myxml.ChildNodes(1). ChildNodes(MyCount). ChildNodes_
(MyIndex). Attributes.Append(oEndOf)
Dim oNote As Xml.XmlAttribute = myxml.CreateAttribute(«Note»)
oNote.InnerText = ListView1.Items(MyIndex). SubItems(3). Text
myxml.ChildNodes(1). ChildNodes(MyCount). ChildNodes_
(MyIndex). Attributes.Append(oNote)
Next
\'Если найден и заполнен требуемый узел Data, прекращаем перебор узлов
Exit For
End If
Next
\'Сохраняем документ в файл
myxml.Save(dirStr + «\2005.xml»)
End Sub21. Остальные процедуры будут не столь объемны. После того как файл был загружен и его содержимое было отображено в элементе ListView, надо написать обработчики событий для щелчков на компонентах PictureBox, которые играют роль кнопок. Поскольку при написании этих обработчиков понадобятся переменные, через которые данные будут передаваться из формы в форму, нужно создать модуль и объявить в нем эти переменные.
22. Выполнить команду Project ? Add Module. На экран будет выведено соответствующее
диалоговое окно. В строке Name нужно вместо предлагаемого имени указать имя Data, после чего нужно нажать кнопку Open. В окне редактора кода будет открыт пустой модуль. В нем нужно указать код, приведенный в листинге 6.10.Листинг 6.10Module Data
Public categorySt, startOfSt, endOfSt, noteSt As String
End Module23. Процедура сохранения информации текущего дня при закрытии приложения описана в листинге 6.11. Листинг 6.11
Private Sub Form1_Closing(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Data_Save(Label1.Text)
End Sub24. Обработчик щелчка на кнопке PictureBox1, который осуществляет переход к предыдущему дню, приведен в листинге 6.12. Листинг 6.12
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles PictureBox1.Click
Data_Save(Label1.Text)
D = DateAdd(DateInterval.Day, – 1, D)
Label1.Text = D.ToShortDateString
Data_Load(D.ToShortDateString)
End Sub25. Обработчик щелчка на кнопке PictureBox2, который осуществляет переход к следующему дню, приведен в листинге 6.13. Листинг 6.13
Private Sub PictureBox2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles PictureBox2.Click
Data_Save(Label1.Text)
D = DateAdd(DateInterval.Day, 1, D)
Label1.Text = D.ToShortDateString
Data_Load(D.ToShortDateString)
End Sub26. Обработчик щелчка на кнопке PictureBox3, который отвечает за добавление очередной записи в текущий день, показан в листинге 6.14. Листинг 6.14
Private Sub PictureBox3_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles PictureBox3.Click
Dim lvIt As ListViewItem
\'Создаем диалоговую форму редактирования
Dim MyForm As New Form2
\'Устанавливаем флаг, показывающий, что был щелчок на кнопке 3
MyForm.Send = 3
\'Если ListView не пустой, копируем значения полей текущей записи в
\'переменные так, что время конца в текущей записи станет временем начала
\'в создаваемой записи
If ListView1.Items.Count > 0 Then
categorySt = ListView1.Items.Item_
(ListView1.Items.Count – 1). SubItems(0). Text
startOfSt = ListView1.Items.Item_
(ListView1.Items.Count – 1). SubItems(2). Text
endOfSt = startOfSt
noteSt = ""
Else
categorySt = ""
startOfSt = ""
endOfSt = ""
noteSt = ""
End If
\'Выводим на экран форму редактирования записи
If MyForm.ShowDialog = DialogResult.OK Then
\'И если редактирование завершилось щелчком на кнопке OK, добавляем новую
\'запись в ListView
lvIt = New ListViewItem(categorySt)
ListView1.Items.Add(lvIt)
ListView1.Items.Item.(ListView1.Items.Count – 1). SubItems.Add(startOfSt)
ListView1.Items.Item.(ListView1.Items.Count – 1). SubItems.Add(endOfSt)
ListView1.Items.Item.(ListView1.Items.Count – 1). SubItems.Add(noteSt)
End If
End Sub27. Обработчик щелчка на кнопке PictureBox4, который отвечает за редактирование текущей записи, показан в листинге 6.15. Листинг 6.15
Private Sub PictureBox4_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles PictureBox4.Click
\'Если в ListView есть выделенная строка, тогда редактируем
If ListView1.SelectedIndices.Count > 0 Then
Dim MyForm As New Form2
\'Сообщаем форме редактирования, что был щелчок на кнопке 4
MyForm.Send = 4
\'Копируем значения полей записи в переменные
categorySt = ListView1.Items(ListView1.SelectedIndices_(0)). SubItems(0). Text
startOfSt = ListView1.Items(ListView1.SelectedIndices(0)). SubItems(1). Text
endOfSt = ListView1.Items(ListView1.SelectedIndices(0)). SubItems(2). Text
noteSt = ListView1.Items(ListView1.SelectedIndices(0)). SubItems(3). Text
\'Если редактирование завершилось щелчком на кнопке OK, копируем возвращенные
\'значения переменных в соответствующие поля ListView
If MyForm.ShowDialog = DialogResult.OK Then
ListView1.Items(ListView1.SelectedIndices(0)). SubItems(0). Text = categorySt
ListView1.Items(ListView1.SelectedIndices(0)). SubItems(1). Text = startOfSt
ListView1.Items(ListView1.SelectedIndices(0)). SubItems(2). Text = endOfSt
ListView1.Items(ListView1.SelectedIndices(0)). SubItems(3). Text = noteSt
End If
End If
End Sub28. Код обработчика щелчка на кнопке PictureBox5 (удаление текущей записи) приведен в листинге 6.16. Листинг 6.16
Private Sub PictureBox5_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles PictureBox5.Click
If ListView1.SelectedIndices.Count > 0 Then
ListView1.Items.Remove(ListView1.Items(ListView1.SelectedIndices(0)))
End If
End Sub29. После того как были написаны обработчики для элементов управления основной формы, нужно сделать то же самое для формы редактирования данных. Сначала нужно объявить в этой форме переменную Send, как показано в листинге 6.17. Лиситнг 6.17
Public Class Form2
…
Public Send As Integer30. Теперь можно написать основные обработчики событий компонентов. Обработчик события загрузки формы должен различать, щелчком на котором элементе была загружена форма, и вести себя соответственно. Это поведение задается в коде, который приведен в листинге 6.18. Листинг 6.18
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
Dim myCount As Integer
Dim myStrTime As String
ComboBox2.Items.Clear
ComboBox3.Items.Clear
\'Загружаем содержимое двух компонентов выпадающих списков, которые
\'должны отображать выбор временных интервалов от 00.00 до 23.55 c
\'дискретностью в 5 минут
For myCount = 0 To 287
Dim myTime1 As TimeSpan = TimeSpan.FromMinutes(myCount * 5)
myStrTime = myTime1.ToString
myStrTime = myStrTime.Substring(0, 5)
ComboBox2.Items.Add(myStrTime)
ComboBox3.Items.Add(myStrTime)
Next
\'Читаем список категорий в ComboBox1
Dim myxmlDoc As New Xml.XmlDocument
Dim dirStr As String
dirStr = IO.Path.GetDirectoryName_
(Reflection.Assembly.GetExecutingAssembly.GetName.CodeBase.ToString)
ComboBox1.Items.Clear
myxmlDoc.Load(dirStr + «\Category.xml»)
For myCount = 0 To myxmlDoc.ChildNodes.Item(1). ChildNodes.Count – 1
ComboBox1.Items.Add_ (myxmlDoc.ChildNodes.Item(1). ChildNodes.Item(myCount). Name)
Next
ComboBox1.SelectedIndex = 0
ComboBox2.SelectedIndex = 0
ComboBox3.SelectedIndex = 0
\'Устанавливаем в ComboBox1 категорию, которая задана в последней
\'строке ListView
For myCount = 0 To ComboBox1.Items.Count – 1
If ComboBox1.Items(myCount) = categorySt Then
ComboBox1.SelectedIndex = myCount
Exit For
End If
Next
\'Для второго и третьего ComboBox так же устанавливаем значения
For myCount = 0 To ComboBox2.Items.Count – 1
If ComboBox2.Items(myCount) = startOfSt Then
ComboBox2.SelectedIndex = myCount
Exit For
End If
Next
For myCount = 0 To ComboBox3.Items.Count – 1
If ComboBox3.Items(myCount) = endOfSt Then
ComboBox3.SelectedIndex = myCount
Exit For
End If
Next
TextBox1.Text = noteSt
End Sub31. Обработчик щелчка на кнопке OK формы редактирования показан в листинге 6.19. Листинг 6.19
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
\'Возвращаем в переменные установленные в элементах управления значения
categorySt = Me.ComboBox1.Text
startOfSt = Me.ComboBox2.Text
endOfSt = Me.ComboBox3.Text
noteSt = Me.TextBox1.Text
\'Возвращаем результат работы диалогового окна
DialogResult = DialogResult.OK
\'Закрываем форму
Me.Close
End Sub32. Код обработчика щелчка на кнопке Cancel формы редактирования приведен в листинге 6.20. Листинг 6.20
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button2.Click
DialogResult = DialogResult.Cancel
Me.Close
End Sub33. Осталось задать код еще двух обработчиков, предназначенных для автоматического отображения и скрытия программной панели ввода (виртуальной клавиатуры) при приобретении и потери фокуса текстовым полем TextBox. Код этих обработчиков приведен в листинге 6.21. Листинг 6.21
Private Sub TextBox1_GotFocus(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles TextBox1.GotFocus
InputPanel1.Enabled = True
End Sub
Private Sub TextBox1_LostFocus(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles TextBox1.LostFocus
InputPanel1.Enabled = False
End Sub