2

明らかにListViewItemsを含むWinForms ListViewがあります。ListView 全体ではなく、各アイテムにクリック イベントをアタッチできるようにしたいと考えています (そして、どのアイテムがクリックされたかを把握しようとしています)。これは、選択された項目に基づいて異なるアクションを実行する必要があるためです。ListViewItem クラスは、この点で非常に制限されているようです。私がやりたいことをする方法はありますか、または ListView.Click イベントを使用する必要がありますか?

4

7 に答える 7

3

私は引き続き ListView Click イベントを使用します。このような状況で私が使用したトリックは、ListViewItem の Tag プロパティを使用することです。アイテムごとのデータを保存するのに最適で、何でも入れることができます。

于 2009-07-14T16:10:15.053 に答える
1

ほとんどのユースケースでは、 aは何らかのオブジェクトの UI での表現であり、ユーザーがクリックしたときに が表すListViewItemオブジェクトのメソッドを実行しようとしています。ListViewItem単純さと保守性のために、ユーザーがマウスをクリックしてから実際にメソッドが実行されるまでの間に存在するものをできるだけ少なくする必要があります。

オブジェクトをListViewItemTagプロパティに格納して Click イベント ハンドラーで参照することはできますが、その結果、コードに固有の弱点がいくつかあります。

private void MyListView_Click(object sender, EventArgs e)
{
   ListView l = (ListView)sender;
   if (l.SelectedItem != null)
   {
      MyClass obj = l.SelectedItem.Tag as MyClass;
      if (obj != null)
      {
         obj.Method();
      }
   }
}

これは、多くのキャストと null 参照チェックです。そして、このコードの本当に弱い点は、それが null であることが判明した場合Tag、またはオブジェクト以外のものが含まれてMyClassいる場合、問題が発生している場所を見つけるためにどこを調べればよいかわからないことです。

次のようなコードと比較してください。

private void MyListView_Click(object sender, EventArgs e)
{
   MyClass.ListViewClicked(sender as ListView);
}

このコードを保守しているとき、そのメソッドがどのように実装されているかはわかりませんListViewClickedが、少なくともどこで検索すればよいかはわかりますMyClass。実行すると、次のように表示されます。

public static void ListViewClicked(ListView listView)
{
   if (listView.SelectedItem == null)
   {
      return;
   }
   if (ListViewItemLookup.ContainsKey(listView.SelectedItem))
   {
      ListViewItemLookup[listView.SelectedItem].Execute();
   }
}

なるほど、興味深いですね。スレッドに続いて、その辞書はどのように入力されますか? MyClass の別のメソッドでそれを見つけます。

private static Dictionary<ListViewItem, MyClass> ListViewItemLookup = 
   new Dictionary<ListViewItem, MyClass>();

public ListViewItem GetListViewItem()
{
   ListViewItem item = new ListViewItem();
   item.Text = SomeProperty;
   // population of other ListViewItem columns goes here
   ListViewItemLookup.Add(item, this);
   return item;
}

(合理的な人々は、クラスが UI での特定の形式の表現に非常に密接に結び付けられることが適切かどうかについて意見が分かれる可能性があります。これらのメソッドとこの辞書を、MyClassそれ自体ではなくヘルパー クラスに分離する人がいます。そして、問題の残りの部分がどれほど毛むくじゃらかによっては、私もそうするかもしれません.)

ListViewこのアプローチにより、多くの問題が解決されます。これにより、の Click イベントを適切に処理する簡単な方法が得られます。ListViewItemしかし、それはまた、最初に を作成するための、必ずしも自明ではないプロセスを分離します。フォームをリファクタリングして別のフォームに移動する場合に移動する必要があるコードの量を減らしますListView。また、フォーム クラスが知る必要があることの数が減ります。これは一般的には良いことです。

また、それはテスト可能です。通常、UI イベント ハンドラーでコードをテストする唯一の方法は、UI を使用することです。このアプローチにより、UI のこの部分を取り巻くすべてのロジックを単体テストできるものに分離できます。単体テストを作成できないのは、フォーム内の 1 行のコードだけです。

ListViewItem人々が提案している他のアプローチ - サブクラス化- もまったく問題ないことを指摘しておく必要があります。GetListViewItemクラスのコンストラクターのメソッドに追加したロジックを配置し、MyClassインスタンスをクラスのプライベート プロパティにして、のメソッドを呼び出す Click メソッドを公開しますMyClass。私が気に入らない唯一の理由は、実際には単体テストできないかなりの量のコードがフォームに残っていることです。

ListView l = (ListView)sender;
if (l.SelectedItem != null)
{
    MyClassListViewItem item = l.SelectedItem as MyClassListViewItem;
    if (item != null)
    {
       item.MyClass.Method();
    }
}
于 2009-07-14T19:17:42.537 に答える
0

ただし、タグ フィールドにデリゲートまたは他のハンドラーへの参照を貼り付けることができる場合があります (ListViewItem のタグ プロパティがあると仮定します)。どの ListViewItem がクリックされたかを判断する必要がありますが、別の決定構造ではなくタグに直接移動できます。

于 2009-07-14T16:08:59.517 に答える
0

ListViewItemから継承する新しいクラス(またはさまざまなタイプがある場合はクラス)を作成し、ListViewにこれらのオブジェクトを入力します(リストビューから継承する限り(いくつかのレベルの継承であっても)、ListViewコントロールはそれらを取ります)。

次に、クリック メソッドをカスタム クラスに追加し、listView の ItemClick イベントで、クリックされた項目のクリック メソッドを呼び出すだけです。(キャストが必要な場合もあります)

于 2009-07-14T16:09:36.940 に答える
0

実際には、ListViewItem を使用する方法はありません。ListView 自体を使用する必要があります。ListView の「SelectedItems」プロパティを使用すると、選択した ListViewItems にアクセスできます。

1 つのオプションは、ListViewItem クラスをオーバーライドして、そこに特定のものを実装することです。次に、選択したアイテムをオーバーライドされたアイテムにキャストして、アクションを実行できます。

于 2009-07-14T16:11:46.203 に答える
0

通常のListView Clickイベントを使用するだけでなく、そうする理由が本当にわかりませんが、あなたが提案するようにする場合は、EventHandlerデリゲートを各ListViewItemのTagプロパティに割り当ててから、ListView Clickイベントでハンドラー ListViewItem.Tag <> null かどうかを確認し、そうであればデリゲートを呼び出します。

于 2009-07-14T16:13:20.973 に答える