4

FileSystemWatcher が変更を通知するので、ObservableCollection を更新しようとしています。クロススレッド操作のため、これが不可能であることはわかっています。
したがって、イベントが発生したときに作成/削除/名前変更されたファイルの名前を取得し、BackgroundWorker で行うように、イベントが完了したら UI スレッドで更新したいと考えています。誰でもこれを行う方法を教えてもらえますか?

また、この FileSystemWatcher を定義して開始する場所を教えてください。現在、MainViewModel で定義しています。

PS: SO で同様の質問を見たことがありますが、明確な全体像が得られませんでした

前もって感謝します、
Veer

4

3 に答える 3

2
public void SomeActionToBeInvokedOnTheMainThread()
{
    if (someControl.Dispatcher.CheckAccess())
    {
        // you can modify the control
    }
    else
    {
        someControl.Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Normal,
            new Action(SomeActionToBeInvokedOnTheMainThread)
        );
    }
}
于 2010-03-03T07:29:38.543 に答える
2

FileSystemWatcher を定義するには、メイン ビュー モデルが適切な場所だと思います。スレッドの問題に関しては、これが簡単な方法です。

_watcher = new FileSystemWatcher(path);
_watcher.Created += (obj, e) =>
  Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
  {
    // Code to handle Created event
  };
_watcher.Changed += (obj, e) =>
  Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
  {
    // Code to handle Changed event
  };
_watcher.Renamed += (obj, e) =>
  Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
  {
    // Code to handle Renamed event
  };
_watcher.Deleted += (obj, e) =>
  Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
  {
    // Code to handle Deleted event
  };
// ...
_watcher.EnableRaisingEvents = true;

「処理するコード」のそれぞれは、UI スレッド内で実行されるため、ObservableCollection. FileSystemEventArgs "e" がこのコード内で使用できることに注意してください。

別のイベント ハンドラー メソッドを使用する場合は、上記のコードから呼び出すか、次の便利なショートカットを使用できます。

var switchThread =
  (FileSystemEventHandler handler) =>
    (object obj, FileSystemEventArgs e) =>
      Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
       handler(obj, e))

_watcher = new FileSystemWatcher(path);
_watcher.Created += switchThread(OnCreated);
_watcher.Changed += switchThread(OnChanged);
_watcher.Deleted += switchThread(OnDeleted);
_watcher.Renamed += switchThread(OnRenamed);
_watcher.EnableRaisingEvents = true;

ここOnCreatedで、OnChangedOnDeletedOnRenamedは、通常のシグネチャを持つ通常のイベント ハンドラー メソッドです。たとえば、次のようになります。

void OnChanged(object sender, FileSystemEventArgs e)
{
  // Code to handle Changed event
}

個人的には、最初の方法を好みます。なぜなら、4 つの余分な 1 行のメソッドを作成するのが好きではないからです。

ビューモデルは、コールバックする Dispatcher を知る必要があることに注意してください。これを行う最も簡単な方法は、上記で想定したように、DispatcherObject からビュー モデルを派生させることです。もう 1 つの方法は、ビュー モデルのコンストラクターまたは FileSystemWatcher イベントを登録するメソッドが Dispatcher.Current のコピーをローカル フィールドまたはローカル変数に格納し、それを .BeginInvoke 呼び出しに使用することです。

また、必要に応じて、ビュー モデルではなくビュー コード ビハインドでまったく同じコードを使用できることにも注意してください。

于 2010-03-03T18:44:43.523 に答える
1

私は Ray B. のアプローチを使用しましたが、少し変更する必要があり、他の人の時間を節約するためにここに更新を投稿すると思いました。

私の VS2010/.NET 4.0 WPF プロジェクトはエラーをスローしていました:

Cannot assign lambda expression to an implicitly-typed local variable

いくつかの調整の後、私は次のことを思いつきました。Renamed イベントを処理するために定義された追加の var に注意してください。

var switchThreadForFsEvent = (Func<FileSystemEventHandler, FileSystemEventHandler>)(
        (FileSystemEventHandler handler) =>
                (object obj, FileSystemEventArgs e) =>
                    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
                        handler(obj, e))));

var switchThreadForFsRenameEvent = (Func<RenamedEventHandler, RenamedEventHandler>)(
            (RenamedEventHandler handler) =>
                (object obj, RenamedEventArgs e) =>
                    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>
                        handler(obj, e))));

_fileSystemWatcher = new FileSystemWatcher(documentCollectionPath);
_fileSystemWatcher.Created += switchThreadForFsEvent(OnFileCreated);
_fileSystemWatcher.Deleted += switchThreadForFsEvent(OnFileDeleted);
_fileSystemWatcher.Renamed += switchThreadForFsRenameEvent(OnFileRenamed);
_fileSystemWatcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName;
_fileSystemWatcher.IncludeSubdirectories = true;
_fileSystemWatcher.EnableRaisingEvents = true;
于 2011-03-27T02:12:06.450 に答える