locked
StorageFolderQueryResult.ContentsChanged Fires Twice

    Question

  • I built an app that is monitoring changes of folders. To do so, I'm using the StorageFolderQueryResult.ContentsChanged event.

    In contrast to other postings, I do not have an issue that the event is not fired. In my case, the event is always fired twice with a time span of one second. I am able to reproduce this on Windows 8 x64, Windows 8.1 x64. and on Windows 8 RT. The time span is always the same, so it seems it does not depend on the hardware.

    Can anyone explain to me why the event is fired twice? And maybe give me an hint on how to avoid it?

    Thanks,

    Stefan

    Here is the implementation of a test sample.

    namespace FileSystemWatcher
    {
      public sealed partial class MainPage : Page
      {
        ObservableCollection<string> ItemList;
    
        private StorageFolderQueryResult QueryResult { get; set; }
    
        public MainPage()
        {
          this.InitializeComponent();
    
          ItemList = new ObservableCollection<string>();
    
          ListView.ItemsSource = ItemList;
        }
    
        protected override void OnNavigatedTo
          (
          NavigationEventArgs args
          )
        {
          QueryResult = KnownFolders.PicturesLibrary
            .CreateFolderQueryWithOptions(new QueryOptions() 
              { FolderDepth = FolderDepth.Shallow });
    
          QueryResult.ContentsChanged += OnFolderContentChanged;
    
          try
          {
            QueryResult.GetFoldersAsync(0, 1);
          }
          catch (Exception)
          {
          }
        }
    
        private void OnFolderContentChanged
          (
          IStorageQueryResultBase sender,
          object args
          )
        {
          Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                () =>
                {
                  ItemList.Add(
                    String.Format("{0:HH:mm:ss.fffffff} - Notification for path >{1}< / name >{2}<", 
                      DateTime.Now, sender.Folder.Path, sender.Folder.Name));
                });
        }
      }
    }

    <Page
        x:Class="FileSystemWatcher.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:FileSystemWatcher"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
      <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <ListView x:Name="ListView" Margin="20"/>
      </Grid>
    </Page>
    

    Thursday, October 31, 2013 2:08 PM

Answers

  • A colleague of mine confirmed what I observed.

    So I reported it as a bug on MS Connect, bug id 808551.

    Regards,

    Stefan

    • Marked as answer by rstg Thursday, November 14, 2013 3:04 PM
    Thursday, November 14, 2013 3:03 PM

All replies

  • I can't say for sure if this specific case is legitimate or not, but it well may. Your app needs to be able to handle the changes as they come. If you watch the files in Process Monitor you should be able to tell if there are multiple changes made to the files during that time.

    The other thing to watch for is multiple event handlers, but that doesn't appear to be the case in your test page (assuming we never navigate away and back to MainPage), and those would probably come closer to each other in time.

    --Rob


    Friday, November 01, 2013 3:13 AM
    Owner
  • Rob,

    I took Process Monitor to see what's happening. To be honest, it was more confusing to me but helpful. Just renaming a folder lead to loads of events.

    So I tried another approach and created a console app, based on the sample code of FileSystemWatcher. The code can be found below.

    Assuming I was using the FileSystemWatcher correctly, all events were fired once for the console app, while the Windows Store app received two events for the same change.

    I would really appreciate if Microsoft could have a closer look at it.

    Thanks,

    Stefan

    using System;
    using System.IO;
    using System.Security.Permissions;
    
    namespace FileSystemWatcherConsole
    {
      class Program
      {
        static void Main(string[] args)
        {
          try
          {
            Run();
          }
          catch (Exception e)
          {
            Console.WriteLine("Caught exception{0}{1}", Environment.NewLine, e);
          }
        }
    
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public static void Run()
        {
          // Create a new FileSystemWatcher and set its properties.
          FileSystemWatcher watcher = new FileSystemWatcher();
          watcher.Path = @"Set the Path to Pictures Library here";
          // Watch all
          watcher.Filter = String.Empty;
    
          // Add event handlers.
          watcher.Changed += new FileSystemEventHandler(OnChanged);
          watcher.Created += new FileSystemEventHandler(OnChanged);
          watcher.Deleted += new FileSystemEventHandler(OnChanged);
          watcher.Renamed += new RenamedEventHandler(OnRenamed);
    
          // Begin watching.
          watcher.EnableRaisingEvents = true;
    
          // Wait for the user to quit the program.
          Console.WriteLine("Press \'q\' to quit the sample.");
          while (Console.Read() != 'q') ;
        }
    
        // Define the event handlers. 
        private static void OnChanged(object source, FileSystemEventArgs e)
        {
          // Specify what is done when a file is changed, created, or deleted.
          Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
        }
    
        private static void OnRenamed(object source, RenamedEventArgs e)
        {
          // Specify what is done when a file is renamed.
          Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
        }
      }
    }


    • Edited by rstg Friday, November 01, 2013 9:10 AM
    Friday, November 01, 2013 9:10 AM
  • Any news on this issue?

    Re-validating the behavior on a Win 8.1 x64 machine I noticed that producing multiple changes in a short time (e.g. create or delete 20-30 folders within a second or two) will lead to two notification with a time span of 6-7 seconds. Any changes within this time do not cause additional notifications.

    Since the notification does not pass any information about what has changed, how can I tell if it is just a duplicate or not without accessing the file system? Reading the folder's content via StorageFolder.GetItemsAsync is not that fast on my machine. E.g. it takes about four seconds to get about 3,500 items from c:\windows\system32.

    Thanks,

    Stefan

    Friday, November 08, 2013 11:23 AM
  • I cannot reproduce this with your sample code.

    That said, the app needs to be able to handle multiple changes in a short time since they may happen in production.

    --Rob

    Saturday, November 09, 2013 1:01 AM
    Owner
  • Just had an additional look at it and noticed there is a difference between files and folders.

    I was always working with folders (create, rename), which lead to the results described above.

    Working with files (create, rename, delete) fires only a single event, what you might have observed.

    Could you please be so kind and try to reproduce this by creating or renaming folders?

    Thanks,

    Stefan



    • Edited by rstg Monday, November 11, 2013 9:02 AM
    Monday, November 11, 2013 9:00 AM
  • A colleague of mine confirmed what I observed.

    So I reported it as a bug on MS Connect, bug id 808551.

    Regards,

    Stefan

    • Marked as answer by rstg Thursday, November 14, 2013 3:04 PM
    Thursday, November 14, 2013 3:03 PM