FileSystemWatcher & Cross-thread   zodpovězená otázka

VB.NET

Zdravim,

narazil jsem na problem pri pouzivani FileSystemWatcher. Problem nastava pri vyvolani udalosti FileSystemWatcher resp. kdyz dojde na praci s komponentou ListView. Kompilator hlasi Cross-thread upozorneni...

Muzete mi nekdo poradit, jak se toho vyvarovat nebo jak pracovat s objekty v jinem vlakne?

Za vsechny odpovedi predem dekuju

Public Sub FileWatcher(ByVal Folder As String)
        Dim watcher As New System.IO.FileSystemWatcher()
        watcher.Path = Folder

        watcher.NotifyFilter = (System.IO.NotifyFilters.LastAccess)

        watcher.Filter = "Test.txt"

        AddHandler watcher.Changed, AddressOf OnChanged

        watcher.EnableRaisingEvents = True
    End Sub

    Private Sub OnChanged(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)

        trayIcon.BalloonTipText = "Zdrojový soubor byl změněn"
        trayIcon.ShowBalloonTip(1)

        Data = LoadData(Data)
        'Nacte data ze souboru a vybere vyhovujici a ulozi je do kolekce

        FillListView()
        'Vlozi objekty z kolekce Data do ListView
    End Sub

Private Sub FillListView()
        lvData.Items.Clear()

        For Each obj As Object In Data
            Dim item As ListViewItem = lvData.Items.Add(obj(0)) 'Cas
            item.SubItems.Add(obj(2)) 'Text

            item.Checked = True
        Next

        For Each item As ListViewItem In lvData.Items
            If item.Index Mod 2 Then item.BackColor = Color.WhiteSmoke
        Next

        'Vyprazdneni kolekce Data
        Data.Clear()
    End Sub

nahlásit spamnahlásit spam 0 odpovědětodpovědět
'Delegát metody pro aktualizaci ListView
Private Delegate Sub FillListViewCallback()
Private Sub FillListView()
  'Jestliže je voláno z nesprávného vlákna
  If InvokeRequired Then
    'Asynchronně spustit příslušnou metodu ve správném vlákně
    BeginInvoke(New FillListViewCallback(AddressOf FillListView))
  'Jestliže je voláno ze správného vlákna
  Else
    'Zabránit zbytečnému překreslování během aktualizace
    lvData.BeginUpdate()
    lvData.Items.Clear()
    For Each obj As Object In Data
      Dim item As ListViewItem = lvData.Items.Add(obj(0))
      item.SubItems.Add(obj(2))
      item.Checked = True
      'Není třeba provádět zbytečně v dalším cyklu
      If item.Index Mod 2 Then item.BackColor = Color.WhiteSmoke
    Next
    'Konec aktualizace, povolit překreslování
    lvData.EndUpdate()
  End If
  Data.Clear()
End Sub

Ideální řešení je zapouzdřit metody spouštěné v jiném vlákně do samostatné třídy a v konstruktoru této třídy uložit System.Windows.Forms.

WindowsFormsSynchronizationContext.Current přes který se potom budou vyvolávat všechny události, to je však vhodné pro vlastní řešení, pro hotové komponenty .NET Frameworku stačí použít výše uvedený příklad.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Diky moc, funguje to... ale narazil jsem jeste na jeden problem. Jde o nacitani dat ze souboru, volam funkci:

Data = LoadData(Data)

ktera vraci kolekci prvku, v podstate cte soubor po radcich a uklada je do kolekce. Problem je v tom, ze kdyz funkci vola event FileSystemWatcheru funkce vrati prazdnou kolekci...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nevidím deklaraci proměnné Data a zdrojový kód metody LoadData, tudíž k tomu nemám co dodat. I když na první pohled se mi zdá řádek Data = LoadData(Data) jako pěkná hovadina...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

jo omlouvam se...

zbytek kodu je v prvnim prispevku

Private Data As New Collection

Private Function LoadData(ByVal coll As Collection) As Collection
        Try
            Dim pole() As String
            Dim Slozka As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
            Slozka = Slozka & "\Neon Systems\Reminders"
            'Vyprazdneni kolekce
            Data.Clear()
            'Otevreni souboru
            Dim soubor As New IO.StreamReader(Slozka & "\reminders.db")
            'Cteni souboru po radcich
            While Not soubor.EndOfStream
                Dim Radek As String = soubor.ReadLine
                pole = Split(Radek, ";")
                'Nova instance tridy Row
                Dim row As New Row
                'Ulozeni hodnot do objektu row
                row.setAll(pole)

                If row.isActuall Then coll.Add(row.getAll)
            End While
            soubor.Close()
        Catch ex As Exception
        End Try

        Return coll
    End Function

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nevím co dělají isActual a getAll třídy Row, tudíž nemůžu říct nic konkrétního kromě toho, že někde v průběhu zpracování dojde k vyjímce která se odchytí v bloku Catch a tudíž se vrátí prázdná kolekce kterou jste předtím smazal metodou Clear. Dále nechápu proč metoda LoadData vrací Collection, když s tou samou instancí Collection pracujete uvnitř metody a proto není nutné jí vracet...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

isActual testuje jestli datum nactene ze souboru je dnesni

    Private strTime As String
    Private strDate As String
    Private strText As String
    Private strTyp As String

    Public Function isActuall() As Boolean
        Dim bActuall As Boolean = False

        Try
            Dim intToday As Integer = Weekday(Date.Now, FirstDayOfWeek.Monday)

            'Podle data
            If strDate.Trim <> "" Then
                Dim intDate As Integer = Date.Compare(CDate(strDate), DateAndTime.DateSerial(Year(Now), Month(Now), DateAndTime.Day(Now)))
                If intDate = 0 Then bActuall = True
            End If

        Catch ex As Exception
        End Try

        Return bActuall
    End Function

setAll uklada data ze souboru do tridy Row

    Public Sub setAll(ByVal pole As String())
        strTime = pole(0)
        strDate = pole(1)
        strText = pole(2)
        strTyp = pole(3)
    End Sub

getAll vraci data ze tridy Row

    Public Function getAll() As Object()
        Dim obj(4) As Object
        obj(0) = strTime
        obj(1) = strDate
        obj(2) = strText
        obj(3) = strTyp

        Return obj
    End Function

A to ze funkce LoadData vraci collection je pozustatek po jistem zameru, ktery jsem nakonec nerealizoval...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Daleko jednodušší a SPOLEHLIVĚJŠÍ porovnání data (porovnává pouze datum, ne čas):

Function IsActual(ByVal anyDate As String) As Boolean
  Dim result As Date
  If Date.TryParse(anyDate, result) Then
    Dim currentdate As Date = DateTime.Now
    With currentdate
      If result.Day = .Day AndAlso result.Month = .Month AndAlso result.Year = .Year Then
        Return True
      Else
        Return False
      End If
    End With
  Else
    Return False
  End If
End Function

Další možné zdroje chyb:

- setAll (nekontroluje platnost a velikost pole a počítá s tím, že bude vždy 4 což nemusí být pravda)

- getAll (alokuje 5 prvků ale používá pouze 4, ve VB se velikost pole udává horní hranicí a ne počtem prvků)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

>>- setAll (nekontroluje platnost a velikost pole a počítá s tím, že bude vždy 4 což nemusí být pravda)<<

obsluzny program uklada do souboru vzdycky 4 prvky na radek, takze tam by snad problem byt nemel...

>>- getAll (alokuje 5 prvků ale používá pouze 4, ve VB se velikost pole udává horní hranicí a ne počtem prvků)<<

to jsem si neuvedomil, dekuju za postreh

to co mi porad nefunguje - funkce LoadData mi nenacte nic pokud ji vyvola event FileSystemWatcher a kompilator nehlasi zadnou chybu, ani try catch box mi nic nechyta..., pokud ji vyvolam napr tlacitkem tak funguje bez problemu

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak potom by mohl být problém v těchto dvou řádcích:

trayIcon.BalloonTipText = "Zdrojový soubor byl změněn"

trayIcon.ShowBalloonTip(1)

Mohlo by se jednat o stejný problém jako v případě ListView - volání vlastností/metod z jiného vlákna než ze kterého byly vytvořeny. Zkuste tyto dva řádky dočasně zakomentovat a uvidíte co se stane.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback