0

Novell のおかげで、FileSystemWatcher を使用してディレクトリの内容の変更を監視できないことがわかったので、独自のバージョンを実装する必要があります。私が抱えている問題の 1 つは、実装が非効率的であるという事実に加えて、UI の ListBox がファイルのリストで更新されないことです。

これが私のフォルダークラスです:

   public class FolderWatcher
   {
    // This collection will contain the files in the folder
    public static AsyncObservableCollection<FileItem> folder = new AsyncObservableCollection<FileItem>();

    // Timer
    System.Timers.Timer timer;

    // Path
    string path;

    // Extension type
    string extension;

    //The next line is important to allow system for us to monitor it.  It's a trust setting, and we need Full Trust.
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public void Run(string dirPath, string extensionFilter)
    {
        // Set path and extension
        path = dirPath;
        extension = extensionFilter;

        // Populate the folder list with the current files
        var dirInfo = new DirectoryInfo(path);
        foreach (var currentFile in dirInfo.GetFiles())
        {
            var aFile = new FileItem
            {
                Name = currentFile.Name,
                Path = currentFile.FullName
            };

            folder.Add(aFile);
        }

        // Start the timer
        timer = new System.Timers.Timer(5000);
        timer.AutoReset = true;
        timer.Enabled = true;

        // When timer elapses, raise an event
        timer.Elapsed += new System.Timers.ElapsedEventHandler(UpdateFiles);
    }

    // Update Files
    private void UpdateFiles(object sender, System.Timers.ElapsedEventArgs e)
    {
        // Get directory info
        var dirInfo = new DirectoryInfo(path);

        // Create a temporary list to hold new items
        AsyncObservableCollection<FileItem> temp = new AsyncObservableCollection<FileItem>();

        // Add the items into the temporary list
        foreach (var currentFile in dirInfo.GetFiles())
        {
            var aFile = new FileItem
            {
                Name = currentFile.Name,
                Path = currentFile.FullName
            };

            temp.Add(aFile);
        }

        // Check for new files first, checking if they've been renamed as well
        int count = temp.Count;
        for (int i = 0; i < count; i++)
        {
            // If main folder list doesn't contain a new file, add it
            if (!folder.Contains(temp[i]))
            {
                folder.Add(temp[i]);
            }
        }

        // Now check to see if any files have been removed
        count = folder.Count;
        for (int i = 0; i < count; i++)
        {
            // If temp folder doesn't contain these files, remove them
            if (!temp.Contains(folder[i]))
            {
                folder.RemoveAt(i);
            }
        }
    }
}

ファイル項目:

public class FileItem : INotifyPropertyChanged
{
    private string _Name;

    public string Name
    {
        get 
        { 
            return _Name; 
        }
        set
        {
            if (_Name != value)
            {
                _Name = value;
                OnPropertyChanged("Name");
            }
        }
    }
    private string _Path;

    public string Path 
    { 
        get { return _Path; }
        set
        {
            if (_Path != value)
            {
                _Path = value;
                OnPropertyChanged("Path");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public override string ToString()
    {
            return _Path;
    }
}

変更された ObservableCollection:

public class AsyncObservableCollection<T> : ObservableCollection<T>
{
    private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;

    public AsyncObservableCollection()
    {
    }

    public AsyncObservableCollection(IEnumerable<T> list)
        : base(list)
    {
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (SynchronizationContext.Current == _synchronizationContext)
        {
            // Execute the CollectionChanged event on the current thread
            RaiseCollectionChanged(e);
        }
        else
        {
            // Post the CollectionChanged event on the creator thread
            _synchronizationContext.Post(RaiseCollectionChanged, e);
        }
    }

    private void RaiseCollectionChanged(object param)
    {
        // We are in the creator thread, call the base implementation directly
        base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
    }

    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (SynchronizationContext.Current == _synchronizationContext)
        {
            // Execute the PropertyChanged event on the current thread
            RaisePropertyChanged(e);
        }
        else
        {
            // Post the PropertyChanged event on the creator thread
            _synchronizationContext.Post(RaisePropertyChanged, e);
        }
    }

    private void RaisePropertyChanged(object param)
    {
        // We are in the creator thread, call the base implementation directly
        base.OnPropertyChanged((PropertyChangedEventArgs)param);
    }
}

更新:上記は更新されたコードです。適切に更新できるように取り組んでいますが、それ以外はすべて問題なく動作しているようです。他の人が使用できるように、完全に機能するようになったら更新します。

古いコードを書き直すことになり、手に負えなくなり、管理が難しくなりました。今のところ文字列を使用していますが、FileItem にも同じように簡単に使用できます...ここにスニペットがあります (これはテスト アプリであるため、ファイルに分割されていません)。

    public MainWindow()
    {
        // Must be used (read MSDN documentation)
        InitializeComponent();

        // Our main collection to hold names of files
        this.dir = new ObservableCollection<string>();

        // Bind our collection to the listbox as the source of data
        TheListBox.ItemsSource = dir;

        // Target directory path
        dirInfo = new DirectoryInfo(@"C:\Temp");

        // Set timer (2 seconds is optimal for overhead and quick updates... increase or decrease based on system performance)
        timer = new System.Timers.Timer(2000);
        timer.AutoReset = true;
        timer.Enabled = true;

        // Add an event handler for timer elapsing
        timer.Elapsed += new System.Timers.ElapsedEventHandler(UpdateFiles);
    }

    // Updates Files in the directory collection
    private void UpdateFiles(object sender, System.Timers.ElapsedEventArgs e)
    {
        // Temporary collection that will help us compare files and avoid errors
        ObservableCollection<string> temp = new ObservableCollection<string>();

        // Since we're using a timer, we have to invoke the changes into the main thread, or we'll get an access exception on dir
        System.Windows.Application.Current.Dispatcher.Invoke(
            DispatcherPriority.Normal,
            (Action)delegate()
            {
                // Populate the temporary collection with files
                foreach (var file in dirInfo.GetFiles())
                {
                    if (!String.IsNullOrEmpty(file.ToString()))
                    {
                        try
                        {
                            temp.Add(file.ToString());
                        }
                        catch (Exception listE)
                        {
                            // log exception
                        }
                    }
                }

                // Check to see if there are any new files
                foreach (var item in temp)
                {
                    if (!dir.Contains(item.ToString()) && !String.IsNullOrEmpty(item.ToString()))
                    {
                        try
                        {
                            dir.Add(item.ToString());
                        }
                        catch (Exception listE)
                        {
                            // log exception
                        }
                    }
                }

                // Check to see if any files have been moved/renamed
                for (int i = 0; i < dir.Count; i++)
                {
                    if (!temp.Contains(dir[i].ToString()) && !String.IsNullOrEmpty(dir[i].ToString()))
                    {
                        try
                        {
                            dir.RemoveAt(i);
                        }
                        catch (Exception listE)
                        {
                            // log exception
                        }
                    }
                }
            });
    }

それは機能し、うまく機能します。エラーはありません。もっと短くする方法はあると思いますが、それはあなた次第です。これを、同様の問題に遭遇した人と共有したいと思いました。

4

1 に答える 1