0

我使用DataGrid绑定到ObservableCollection源来显示两列,一个文件名和一个从分析文件中获得的数字。

    ObservableCollection<SearchFile> fileso;

    //...

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        /* Get all the files to check. */
        int dirCount = searchFoldersListView.Items.Count;
        List<string> allFiles = new List<string>();
        for(int i = 0; i < dirCount; i++)
        {
            try
            {
                allFiles.AddRange(Directory.GetFiles(searchFoldersListView.Items[i].ToString(), "*.txt").ToList());
                allFiles.AddRange(Directory.GetFiles(searchFoldersListView.Items[i].ToString(), "*.pdf").ToList());
            }
            catch
            { /* stuff */ }
        }

        /* Clear the collection and populate it with unchecked files again, refreshing the grid. */
        this.Dispatcher.Invoke(new Action(delegate
        {
            fileso.Clear();
            foreach(var file in allFiles)
            {
                SearchFile sf = new SearchFile() { path=file, occurrences=0 };
                fileso.Add(sf);
            }
        }));

        /* Check the files. */
        foreach(var file in allFiles)
        {
            this.Dispatcher.Invoke(new Action(delegate
            {
                int occurences;
                bool result = FileSearcher.searchFile(file, searchTermTextBox.Text, out occurences);

                fileso.AddOccurrences(file, occurences);  // This is an extension method that alters the collection by finding the relevant item and changing it.
            }));
        }
    }

    //...

    public static void AddOccurrences(this ObservableCollection<SearchFile> collection, string path, int occurrences)
    {
        for(int i = 0; i < collection.Count; i++)
        {
            if(collection[i].path == path)
            {
                collection[i].occurrences = occurrences;
                break;
            }
        }
    }

    //...

    public static bool searchTxtFile(string path, string term, out int occurences)
    {
        string contents = File.ReadAllText(path);
        occurences = Regex.Matches(contents, term, RegexOptions.IgnoreCase).Count;
        if(occurences>0)
            return true;
        return false;
    }

    public static bool searchDocxFile(string path, string term, out int occurences)
    {
        occurences = 0;

        string tempPath = Path.GetTempPath();
        string rawName = Path.GetFileNameWithoutExtension(path);
        string destFile = System.IO.Path.Combine(tempPath, rawName + ".zip");
        System.IO.File.Copy(path, destFile, true);

        using(ZipFile zf = new ZipFile(destFile))
        {
            ZipEntry ze = zf.GetEntry("word/document.xml");
            if(ze != null)
            {
                using(Stream zipstream = zf.GetInputStream(ze))
                {
                    using(StreamReader sr = new StreamReader(zipstream))
                    {
                        string docContents = sr.ReadToEnd();
                        string rawText = Extensions.StripTagsRegexCompiled(docContents);
                        occurences = Regex.Matches(rawText, term, RegexOptions.IgnoreCase).Count;
                        if(occurences>0)
                            return true;
                        return false;
                    }
                }
            }
        }
        return false;
    }

    public static bool searchFile(string path, string term, out int occurences)
    {
        occurences = 0;
        string ext = System.IO.Path.GetExtension(path);

        switch(ext)
        {
            case ".txt":
                return searchTxtFile(path, term, out occurences);
            //case ".doc":
            //    return searchDocFile(path, term, out occurences);
            case ".docx":
                return searchDocxFile(path, term, out occurences);
        }
        return false;
    }

但问题是,有时,当我点击更新按钮(使用上面的 do_work 方法启动工作人员)时,有时,我在数字列中得到随机零而不是正确的数字。这是为什么?我假设这是因为两次更新数字列存在一些问题,有时在实际更新后应用第一次归零,但我不确定细节。

4

1 回答 1

1

我认为这是访问修改后的闭包的情况

        /* Check the files. */
        foreach(var file in allFiles)
        {
            var fileTmp = file; // avoid access to modified closure
            this.Dispatcher.Invoke(new Action(delegate
            {
                int occurences;
                bool result = FileSearcher.searchFile(fileTmp, searchTermTextBox.Text, out occurences);

                fileso.AddOccurrences(fileTmp, occurences);  // This is an extension method that alters the collection by finding the relevant item and changing it.
            }));
        }

基本上发生的事情是您将文件变量传递给 lambda 表达式,但是在实际调用操作之前,foreach 循环将修改文件,使用临时变量来保存文件应该可以解决这个问题。

于 2012-11-13T11:11:36.993 回答