質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

WPFフォルダー監視 STAエラー

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 345

Yukj

score 43

フォルダー監視を実行すると
エラー内容
System.InvalidOperationException: '呼び出しスレッドは、多数の UI コンポーネントが必要としているため、STA である必要があります。'
のエラーが表示されます。

そして調べていくと下記サイトのコードでは起動を確認しましたが引数を入れて実行したのですがどのようにすればいいでしょうか?
https://stackoverrun.com/ja/q/3415117

//動作確認できているコード
public static void OnChanged(object source, FileSystemEventArgs e)
{
       var d = Application.Current.Dispatcher;
       if (d.CheckAccess())
           OnChangedInMainThread();
       else
           d.BeginInvoke((Action)OnChangedInMainThread);


}

void OnChangedInMainThread()
{
       var imagePreview = new ImagePreview();
       imagePreview.Show();
}
////実現したいコード
//引数を追加


       var d = Application.Current.Dispatcher;
       if (d.CheckAccess())
           OnChangedInMainThread(e);//FileSystemEventArgsの引数e
       else
           d.BeginInvoke((Action)OnChangedInMainThread);////この部分にFileSystemEventArgsの引数eを追加して実行したいです。
}
void OnChangedInMainThread(FileSystemEventArgs e)
{
       var imagePreview = new ImagePreview();
       imagePreview.Show();
}
////

よろしくお願いします。

///追記FileSystemWatcherイベント連続発火対策について

private private ImagePreview imagewindow= null;//サブウィンドウをnullに



        private void OnChanged(object sender, FileSystemEventArgs e)//FileSystemWatcherイベント発火
        {
            Dispatcher.BeginInvoke((Action<FileSystemEventArgs>)OnChangedInMainThread, e);//これ(メイン処理)を実行
        }



private void OnChangedInMainThread(FileSystemEventArgs e)//メイン処理
{
  if (imagewindow== null)//imagewindowがnullだった場合imagewindowを開く
      {
        imagewindow= new ImagePreview ();
        imagewindow.Closed += (fomsend, err) => { imagewindow= null; };//ImagePreview が閉じたことを通知してimagewindowをnullにする
        imagewindow.Owner = this;//親子関係
        imagewindow.Show();
      }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

端的に言うと↓です。

BeginInvoke((Action<FileSystemEventArgs>)OnChangedInMainThread, e);

ほかの点はコード中のコメントに入れました。

using System;
using System.IO;
using System.Windows;
using System.Windows.Threading;

namespace Questions273634
{
    public partial class MainWindow : Window
    {
        private int count;

        public MainWindow()
        {
            InitializeComponent();

            var watcher = new FileSystemWatcher(Environment.CurrentDirectory);
            watcher.NotifyFilter = NotifyFilters.LastWrite;
            watcher.Changed += OnChanged;
            watcher.EnableRaisingEvents = true;

            // 検証がめんどくさいので自分でファイル変更
            var timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += (s, e) => File.WriteAllText(@"test.txt", "aaaa");
            timer.Start();
        }

        private void OnChanged(object sender, FileSystemEventArgs e)
        {
            // このメソッドがWindowのメソッドでないか、static限定なら
            // Application.Current.Dispatcher.BeginInvokeを使う
            // Windowのメソッドならthis.Dispatcher.BeginInvokeでいい

            // 指定しない限り別スレッドになるので、CheckAccessの確認は無駄な気がする

            Dispatcher.BeginInvoke((Action<FileSystemEventArgs>)OnChangedInMainThread, e);
            //Dispatcher.BeginInvoke((Action)(() => OnChangedInMainThread(e))); // ラムダで
            //Dispatcher.Invoke(() => OnChangedInMainThread(e)); // 同期 ラムダで
        }

        private void OnChangedInMainThread(FileSystemEventArgs e)
        {
            //new ImagePreview().Show();

            // xamlに<TextBlock x:Name="textBlock" />があるとして
            textBlock.Text = $"{e.Name} {DateTime.Now:yyyy/MM/dd HH:mm:ss.ffff} {count++}";
        }
    }
}

FileSystemWatcherは連続してイベント発火する場合がある(書き込んだアプリによるのでこちらで制御できない)ようなので、Show()だとちょっと困ったことになるかもしれません。
厳密にやろうとすると、かなり面倒&これといって決定版がない気がします。

簡易でいい場合は、↓なんかがスマートです。
FileSystemWatcherの連続して発生する同じ種類のイベントを無視る - かずきのBlog@hatena

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/02 09:55

    まさにこれです。BeginInvoke((Action<FileSystemEventArgs>)OnChangedInMainThread, e);
    これが知りたかったです。ありがとうございます。
    ここまで丁寧に回答していただいて本当に感謝です。
    連続イベント発火対策を追記しました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る