Отслеживание прошедшего времени для набора задач

Я пытаюсь написать небольшое приложение VB.NET для проведения кросс-командного исследования времени в движении в работе. Мне нужна возможность запуска нескольких таймеров для отдельных задач, и когда пользователь завершит свои задачи, он может завершить их, и они будут сохранены в файле CSV. Я могу делать это с отдельными задачами одновременно, и это уже давно работает в бизнесе. Каков наилучший способ запуска нескольких задач одновременно. У меня возникла идея добавить задачи в список и использовать событие двойного щелчка в качестве функции завершения задачи. Однако я не могу заставить таймеры работать независимо. Кто-нибудь может помочь? Имеет ли это смысл?

Это основная часть работы в этом классе. Если это не имеет смысла, я извиняюсь заранее. Я не программист по профессии, это просто хобби, которое я практикую в работе.

Другое дело, чтобы подсчитывать прошедшие секунды в реальном времени, я могу сделать это с помощью метки, но теоретически мне понадобится неограниченное количество задач...

Public Class runningTask
    Dim timenow As DateTime = Now
    Dim elapsed
    Dim localTask = GlobalVars.task

    Public Sub AddItem()
        CreateTimer()

        Dim str(3) As String
        Dim itm As ListViewItem

        str(0) = localTask
        str(1) = timenow
        str(2) = elapsed

        itm = New ListViewItem(str)

        frmTime.lvTimers.Items.Add(itm)
    End Sub

    Private Sub CreateTimer()
        Dim tmr As New Timer
        tmr.Interval = 1000
        tmr.Enabled = True
        AddHandler tmr.Tick, AddressOf GlobalTimerTick
    End Sub

    Private Sub GlobalTimerTick(ByVal sender As Object, ByVal e As EventArgs)
        Dim t As TimeSpan = Now - timenow
        elapsed = String.Format("{0:00}:{1:00}:{2:00}:{3:00}", Math.Floor(t.TotalHours), t.Minutes, t.Seconds, t.Milliseconds)
    End Sub

End Class

person tom_bea    schedule 09.10.2014    source источник


Ответы (1)


Я выбрал более ООП-подход, который может быть более экономичным с точки зрения таймеров, но имеет очень простой интерфейс. Ядром является TaskItem, который отслеживает задание и время, а затем класс коллекции, чтобы их выставлять, запускать и останавливать. Спрятав как можно больше функций на как можно более низком уровне, все становится проще.

Я использовал только один таймер и не понимаю, зачем вам нужно несколько таймеров для одной задачи. Если TaskItem записывает DateTime при запуске (это происходит автоматически, когда он создается в моем), то вам вообще не нужны никакие таймеры. Прошедшее время всегда рассчитывается с использованием StartedTime и либо DateTime.Now (для текущей задачи), либо CompletedTime для завершенных задач. Я не вижу, где таймер что-то добавляет.

Вам придется сделать много модов для ваших целей. Это не сохраняет завершенные элементы и не удаляет их из списка, но может дать вам отправную точку. Это также вещь первого прохода; тут и там наверняка есть проблемы.

Imports System.Collections.ObjectModel

Public Class Tasks

    ' slight overkill
    Private Enum LVGroups
        Running
        Completed
    End Enum

    Public Enum TaskJobs
        SweepFloor
        BuildRobot
        CleanOven
        RepairRobot
        EmptyTrash
        TeachRobotToTalk
        MakeCoffee
        TeachRobotToWalk
        WashDishes
        TeachRobotVisualBasic
    End Enum

    ' class for a single task
    Public Class TaskItem
        ' these ought to be readonly; so no cheating
        Public Property ID As String
        Public Property EmpName As String

        Public Property StartedTime As DateTime
        Public Property CompletedTime As DateTime

        ' or job code...
        Public Property Job As TaskJobs

        ' put in a ClassLib or Namespace
        Friend Sub New(sName As String, tj As TaskJobs)
            EmpName = sName
            Job = tj

            StartedTime = DateTime.Now
            CompletedTime = DateTime.MaxValue
            ID = System.Guid.NewGuid.ToString
        End Sub

        Public Function IsActive() As Boolean
            Return (CompletedTime = DateTime.MaxValue)
        End Function

        Public Sub EndTask()
            CompletedTime = DateTime.Now
        End Sub

        Public Function GetElapsed() As String
            Dim t As TimeSpan
            If IsActive() Then
                t = DateTime.Now - StartedTime
            Else
                t = CompletedTime - StartedTime
            End If
            Return String.Format("{0:00}:{1:00}:{2:00}", Math.Floor(t.TotalHours),
                                                 t.Minutes, t.Seconds)
        End Function

        Public Overrides Function ToString() As String
            Return String.Format("{0} {1} {2}", EmpName, Job.ToString, GetElapsed)
        End Function

    End Class


    Private col As Collection(Of TaskItem)

    Private myLV As ListView

    ' assign the LV when tasks are created
    Public Sub New(lvTask As ListView)
        myLV = lvTask
        col = New Collection(Of TaskItem)
    End Sub

    ' add new task with EmpName and JobCode
    Public Sub NewTask(sName As String, tj As TaskJobs)

        Dim ti As New TaskItem(sName, tj)
        col.Add(ti)

        ' LV layout: empname, job, elapsed, ID
        ' but only 3 columns so that ID is "hidden"

        Dim lvi As New ListViewItem(ti.EmpName)
        lvi.SubItems.Add(ti.Job.ToString)
        lvi.SubItems.Add(ti.GetElapsed)
        lvi.SubItems.Add(ti.ID)

        lvi.Group = myLV.Groups(LVGroups.Running.ToString)
        myLV.Items.Add(lvi)

    End Sub

    ' called from dbl click on a running task item
    Public Sub StopTask(lvi As ListViewItem)

        Dim ti As TaskItem = (From t In col Where t.ID = lvi.SubItems(3).Text).First

        ' the form doesnt check the status, so we must
        If ti.IsActive Then
            ti.EndTask()
            lvi.Group = myLV.Groups(LVGroups.Completed.ToString)
        End If

    End Sub

    ' called from the form timer tick event
    Public Sub UpdateDisplay()
        Dim ti As TaskItem

        ' iterate items to get ID of runners
        For Each lvi As ListViewItem In myLV.Groups(LVGroups.Running.ToString).Items
            ' ToDo add error checking

            ti = (From t In col Where t.ID = lvi.SubItems(3).Text).First
            lvi.SubItems(2).Text = ti.GetElapsed

        Next

    End Sub

    Public Function RunnersCount() As Integer
        Return GetActiveList.Count
    End Function

    Public Function GetCompletedList() As List(Of TaskItem)
        ' long form
        Dim tList As New List(Of TaskItem)

        For Each ti As TaskItem In col
            If ti.IsActive = False Then
                tList.Add(ti)
            End If
        Next

        Return tList

        ' short form
        'Dim list = (From t In col Where t.IsActive = False).ToList
    End Function


    Public Function GetActiveList() As List(Of TaskItem)
        ' long form
        'Dim tList As New List(Of TaskItem)

        'For Each ti As TaskItem In col
        '    If ti.IsActive Then
        '        tList.Add(ti)
        '    End If
        'Next   
        'Return tList

        ' short form
        Dim list = (From t In col Where t.IsActive).ToList
        Return list

    End Function
End Class

Применение:

Public Class Form1

    Private myTasks As Tasks

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        myTasks = New Tasks(Me.lvTask)
        cboTask.Items.AddRange([Enum].GetNames(GetType(Tasks.TaskJobs)))
    End Sub

Добавьте задачу:

myTasks.NewTask(cboEmp.Text, CType(cboTask.SelectedIndex, Tasks.TaskJobs))

Остановить задачу:

' called from LV mousedoubleclick, so determine the item
Dim lvi As ListViewItem = lvTask.GetItemAt(e.X, e.Y)
myTasks.StopTask(lvi)

Очевидно, что остановка задачи может автоматически добавить данные в файл экспорта. Эта функциональность будет в классе сбора задач, где она будет выполняться непосредственно перед удалением задачи из коллекции (необязательно — они ничего там не повреждают, пока вы можете отличить активные от завершенных).

Событие таймера:

    myTasks.UpdateDisplay()

введите здесь описание изображения

Наконец, включите Option Strict, тем более что люди будут принимать решения на основе результатов проекта.

person Ňɏssa Pøngjǣrdenlarp    schedule 10.10.2014
comment
Спасибо, в конце концов у меня это действительно заработало. Я использовал DataGridView и просматривал строки в тиковом событии моего таймера. Работает отлично, жаль, что я не забыл проверить ответы, так как ваше решение очень хорошее. Спасибо за вашу помощь! - person tom_bea; 17.10.2014
comment
рад помочь - управление (LV vs DGV) не имеет значения, так как принцип тот же. и никогда не поздно принять/проверить ответ, когда они помогут. - person Ňɏssa Pøngjǣrdenlarp; 17.10.2014
comment
Спасибо! Все работает сейчас и отправляет на sharepoint для отчетности. - person tom_bea; 17.10.2014