0

プログラムで達成しようとしているのは、特定のプロセスが実行されているかどうかを知ることです (実行中のすべてのインスタンスについて知る必要があります)。それらをコンボボックスに保持し、オブジェクトとして保存して、後でキャストできるようにします。これは簡単だと思いましたが、結局のところ、頭痛の種になりました:P これがどのように行われるべきかはわかりませんが、機能しています. ただし、このコード ソリューションについては残念です。私はこれに適したプログラミングパターンを知りません。これが、仲間のコーダーに助けを求める理由です。

最初に頭に浮かんだのは、タイマーを使用してプロセスを頻繁にチェックして追加し、Exited イベントを使用してそれらをコンボボックスから削除することです。だからここにタイマーのティックイベントに関する私のコードがあります:

    private void timer_ProcessCheck_Tick(object sender, EventArgs e)
    {
        Process[] tmpArray = Wow_getCurrentlyRunning(); // this returns Process[]
        if (comboBox_processes.Items.Count == 0)
        {
            if (tmpArray.Count() > 0) 
                for (int Index = 0; Index < tmpArray.Count(); Index++)
                    Add(tmpArray[Index]); // adding to combobox
        }
        else
        { 
            if (tmpArray.Count() > comboBox_processes.Items.Count)
            {
                List<Process> result;
        /*Diff compares the two array, and returns to result variable.*/
                if (Diff(tmpArray, comboBox_processes, out result))                 
                    foreach(Process proc in result)
                        Add(proc); // adding to combobox
            }
        }
    }

そして、私の Diff メソッドは次のようになり、差分が diff 変数に入れられます。

    public bool Wow_differsFrom(Process[] current, ComboBox local, out List<Process> diff)
    {
        List<int> diffIndex = new List<int>();

        foreach (Process proc in current)
            diffIndex.Add(proc.Id);

        for (byte Índex = 0; Índex < current.Count(); Índex++)
        {
            for (byte Index = 0; Index < local.Items.Count; Index++)
            {
                if (current[Índex].Id == (local.Items[Index] as Process).Id)
                {
                    diffIndex.Remove(current[Índex].Id);
                    break;
                }
            }
        }

        diff = new List<Process>();

        for (int x = 0; x < current.Count(); x++)
            for (int i = 0; i < diffIndex.Count; i++)
                if (current[x].Id == diffIndex[i])
                    diff.Add(current[x]);

        if (diff.Count == 0)
            return false;
        return true;
    }  

これは、プロセスの終了時に呼び出される Exited イベント ハンドラーです。

    private void Wow_exitedEvent(object o, EventArgs e)
    {
        RemoveCBItem(comboBox_processes, (o as Process).Id); // this will remove the process from combobox, also threadsafe.
    }

私の質問:

  1. これをどのように行いますか?私はこれに近づいていますか?私は感じています、私はしません。

  2. アプリ起動のイベントはありますか?出口用のものがあるように。多分Win32 APIの奥深くですか?

4

1 に答える 1

1

一般的に、アクティブなプロセスのリストを毎回更新する必要がある場合、その考えは正しいと思います。したがって、タイマーを使用してリストを更新しても問題ありません。Win32 API はよくわかりませんが、誰かが process_run と process_retminate の wineows イベントをサブスクライブできるとしたら、セキュリティ上の問題になると思います。

しかし、本当にそれを常に更新する必要がありますか? コンボボックスが展開されたときだけプロセスリストを読むだけで十分でしょうか?ユーザーが次に展開するときに、アイテムを再度初期化します。この方法なら問題は少ないと思います。

あなたの実装に関しては、最も効率的でエレガントではないと思います:

  1. Process オブジェクト全体をコンボボックス項目に格納するのは、私にとっては良くありません。必要なプロパティ (プロセス ID、プロセス名) のみを格納するクラスを作成することをお勧めします。
  2. ループで current.Count() を使用するのは非常に非効率的です。これは、呼び出し時に常に IEnumerable を反復する拡張メソッドです。だからあなたの

    for (byte Íindex = 0; Índex < current.Count(); Índex++)

    O(N*N) の複雑さになります。幸いなことに、プロセス数はアプリケーションに大きな影響を与えるほど大きくはありませんが、この事実を知って、このメソッドをループで使用することに慣れないようにする必要があります。配列であるため、代わりに current.Length を使用してください。

  3. コレクションの同期が複雑すぎて奇妙です。変更するコレクションと初期化するコレクションを受け取り、追加と削除の操作を使用して最初のコレクションを 2 番目のコレクションと等しくするメソッドを作成してみませんか? 両方のコレクションをいくつかのプロパティ (プロセス名など) で並べ替えます。これは、バイナリ検索を使用して非常に簡単かつ効率的に行うことができます。WPF では、ObservableCollection を dataSource として使用して、このアプローチを最も効果的に使用できます。WinForms では、おそらく変更通知でコレクションを使用することもできますが、私はそれらを使用していません。

もっと簡単にできます:

//Somewhere in Form_Load
combobox.DisplayMember = "Name";//name of the property in your MyProcessInfo class
combobox.ValueMember = "Id";//name of the property in your MyProcessInfo class

//In your timer.Tick handler
combobox.DataSource = Wow_getCurrentlyRunning().Select(p=>new MyProcessInfo(p.Id, p.Name)).ToList();

ただし、コンボボックスといくつかの点滅が可能な場合、このアプローチは常にすべてのアイテムを再初期化します。

于 2012-05-10T14:55:04.357 に答える