- PR -

ListViewのチェックボックスのみ使用不可にする

1
投稿者投稿内容
桜緋女
常連さん
会議室デビュー日: 2004/09/15
投稿数: 46
投稿日時: 2005-12-15 17:15
お世話になっております、桜と申します。
現在、VB.NETでListViewを継承したコントロールに、
スクロールは使用可・チェックボックスのみを
ユーザ操作不可にしようとしておりますが、苦戦中です。

これまで試したのは、以下のような感じです。
@Enabled = Falseにする
  ⇒スクロール機能が使えなくなり、NG

AItemCheckedイベントで以下の処理を行う
If _AfReadOnly = True Then
 e.NewValue = e.CurrentValue
End If
  ⇒プログラムからもチェック状態を変えられなくなり、NG。

BSetStyleを使用する
MyBase.SetStyle(ControlStyles.Selectable, Not Value)
MyBase.SetStyle(ControlStyles.UserMouse, Value)
MyBase.UpdateStyles()
MyBase.RecreateHandle()
 ⇒効果なし

C継承コントロールでやるのをあきらめて、
Panel + ListView + VScrollBarを組み合わせたユーザコントロールで実現する
 ⇒動作的には実現できたが、既存ソースでのコントロールの置換えが発生するため、
継承でできるのならばやはり継承でやりたい。

Dプログラムからチェック状態を設定する間は、
呼び出し側で必ず読取専用フラグを倒すようにする。
チェック状態の設定が終わったら、再び読取専用フラグを立てる。
 ⇒実現可能だが、共通部品の動作としてはイマイチ、ウツクシクない。

何かこの機能について、なにか他の案があればお聞かせいただけますか。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-12-15 17:54
最も、簡単な案 (手抜き?) ですが、

引用:

桜緋女さんの書き込み (2005-12-15 17:15) より:

(5) プログラムからチェック状態を設定する間は、
呼び出し側で必ず読取専用フラグを倒すようにする。
チェック状態の設定が終わったら、再び読取専用フラグを立てる。
 -> 実現可能だが、共通部品の動作としてはイマイチ、ウツクシクない。


これは呼び出し側でやっているから「ウツクシクない」んです。
元々本来の CheckBox の動きとは異なるのですから、別名のプロパティを定義して、
そこで内部的にフラグを倒してやって変更を適用しては如何でしょうか?

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
桜緋女
常連さん
会議室デビュー日: 2004/09/15
投稿数: 46
投稿日時: 2005-12-15 19:39
じゃんぬねっと様

 なるほど。
 
 読み取り専用フラグを倒す処理をコントロール側でやるには、
ListViewItemのCheckedプロパティを継承しないといけないのか?とか思っていましたが、
新しいプロパティORメソッドを用意したほうが早そうですね。

 極力既存の呼び出し側ソースにコントロール呼び出し側に手を加えないで、
デザイン画面で読取専用プロパティをTrueにするだけで済ませたいな、
と思っていましたが、この方針が却って手間を増やすだけなら意味ないですね。

 その方向で進めてみます。
 じゃんぬねっとさん、ありがとうございました。

 ちなみに、こんな案もかんがえていました。

 (2)の処理に該当コントロールにフォーカスがある場合、という条件を足す。
 (前提条件)
初期化時にたまたま該当コントロールにフォーカスがあたってる場合を除けば、
コードからチェックボックスを操作する時には
たいていCommandButton等にフォーカスがあたっているだろう.
 マウスの座標と対象アイテムのエリアが被っているか、等の条件を狭めていけば、
危なっかしいけどまあ何とかなるものになるかも知れない・・・?
 やっぱり没ですね。動作の保証が賭けになる共通コントロールなんてイヤだし。

じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2005-12-15 19:47
引用:

桜緋女さんの書き込み (2005-12-15 19:39) より:

極力既存の呼び出し側ソースにコントロール呼び出し側に手を加えないで、
デザイン画面で読取専用プロパティをTrueにするだけで済ませたいな、
と思っていましたが、この方針が却って手間を増やすだけなら意味ないですね。


新しいプロパティやメソッドを定義したのであれば、既存のソースに置き換えるだけですよね?
置換コマンドを利用すれば、確実にスピーディに置き換えれますから手間じゃないですよ。

漏れが心配であれば、オーバーライドまたは属性を使って、
既存のメソッドやプロパティを隠してしまえば、コンパイル エラーになります。

# あ、継承コントロールになるということは、
# コントロールの型も変えないといけないので無意味ですね。(^-^A)

引用:

危なっかしいけどまあ何とかなるものになるかも知れない・・・?
やっぱり没ですね。動作の保証が賭けになる共通コントロールなんてイヤだし。


そうですね。
危なかっしいですし、今後の保守に響いてきそうですのでやめましょう。(^-^;)

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
桜緋女
常連さん
会議室デビュー日: 2004/09/15
投稿数: 46
投稿日時: 2005-12-15 23:38
お世話になります、桜です。

とりあえずこんな感じで、機能的に納得のいくモノができました。
まあ、まださくっと動作確認しただけですが。

全てのメソッドを置き換えるべきかどうかは、ただいま調査中です。
ただ、もともと継承コントロールはあって、そこに機能を追加する形になりますので、
置換えは難しくないと思います。

継承コントロールの中だけを変えて
呼出しを一行たりとも変えたくないという方針にこだわると、
結局却って手間がかかるかも。
だからお勧めいただいた案のほうがよさそうですね。
といいたかったのですが、
分かりづらい文章で失礼いたしました。


コード:
Public Class myListView
 Inherits System.Windows.Forms.ListView

#Region " コンポーネント デザイナで生成されたコード "
 ' 省略
#End Region

 Private _readOnly As Boolean

 Public Property [ReadOnly]() As Boolean
  Get
   Return _readOnly
  End Get
  Set(ByVal Value As Boolean)
   _readOnly = Value
  End Set
 End Property

 Private Sub myListView_ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles MyBase.ItemCheck
  If Me._readOnly Then
   ' 読取専用プロパティ設定時はチェック状態変更不可
   e.NewValue = e.CurrentValue
  End If
 End Sub

 Public Property CheckedEnForce(ByVal index As Integer) As Boolean
  Get
   Return MyBase.Items(index).Checked
  End Get
  Set(ByVal Value As Boolean)
   Dim isReadOnly As Boolean
   Try

    ' 現在の読取専用設定を退避
    isReadOnly = Me.ReadOnly

    ' 強制的にチェック状態を設定するため、一旦読取専用設定を解除する
    Me.ReadOnly = False

    MyBase.Items(index).Checked = Value

    ' 元の読取専用設定に戻す
    Me.ReadOnly = isReadOnly

   Catch ex As Exception
    MessageBox.Show(ex.ToString)
   End Try
  End Set
 End Property

End Class

桜緋女
常連さん
会議室デビュー日: 2004/09/15
投稿数: 46
投稿日時: 2005-12-21 15:58
お世話になります。桜です。

その後、問題発生&解決したのでご報告を。
似たようなことをやろうと思った人の参考になれば幸いです。

-------------------------------------------------------------------
[問題点]
ListViewのItemCheckイベントは、最初に描画を行う際に呼び出される。
そのため、タブコントロールを使ったりしてフォームの起動時に
ListViewが隠れていると、ListViewの存在するタブをアクティブにするまで
ItemCheckが発生しない。
そのためItemCheckイベントが処理されるときには読取専用フラグがたっており、
画面起動からタブ選択の間に変更した値が無効になる。

これは、Application.DoeventsやMe.Refresh、Me.Updateを行っても同じ。
また、MyBase.OnItemClickを呼び出すとItemClickイベントは走るが、
次にItemClickイベントが走る際のItemClickEventArgs.CurrentValueは、
OnClickを呼ばない場合と同じ。

[回避策]
 追加した強制チェックプロパティからの値のセットの際、
強制フラグを追加。
 ItemClickが呼び出された際、該当インデックスに強制フラグがたっていたら、
Check状態の変更を有効にする。
--------------------------------------------------------------------------

 わざわざ報告するにはベタな回避策だなあ、とは思いつつ、
 ItemCheckイベントが最初にコントロールが表示されるまで走らない、というのは
同じような処理をしようと思った人が同じように嵌りそうだとおもったので
あえて投稿しておきます。
1

スキルアップ/キャリアアップ(JOB@IT)