前口上
前稿を受けて、サブクラス化にてカラム直接編集を実現してみたいと思います。
序なので、ふっかちゃんバージョンも紹介しときましょう。
ただ、実はふっかちゃん、MSのサイトからうまくコピーできないパターンがあります。(改行がぐちゃぐちゃで…)
copyしてくる時はちょっと古めの下記サイトを参照してください。(両方必要です)
あ、後 Win32
の中に
[DllImport("coredll.dll")]
ってのが11ヶ所ありますが、何か宜しくないので、
[DllImport("user32.dll")]
に変えて下さい。問題ない筈です。
ふっかちゃん
前稿のコードに前出ふたつのコードを合わせた上で、以下の様にコードを追加すればOKです。
public Form1() {
InitializeComponent();
// 次の2行を追加する
WndProcHooker.HookWndProc(listView1, new WndProcHooker.WndProcCallback(WM_Hook_Handler), WM_HSCROLL);
WndProcHooker.HookWndProc(listView1, new WndProcHooker.WndProcCallback(WM_Hook_Handler), WM_VSCROLL);
}
const int WM_HSCROLL = 0x114;
const int WM_VSCROLL = 0x115;
int WM_Hook_Handler(IntPtr hwnd, uint msg, uint wParam, int lParam, ref bool handled) {
Control.FromHandle(hwnd).Focus();
return -1;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
WndProcHooker.UnhookWndProc(listView1, WM_VSCROLL);
WndProcHooker.UnhookWndProc(listView1, WM_HSCROLL);
}
ListView
のスクロールバーを触ると、直接編集ちっくモード抜けたでしょ?
ふっかちゃん、中々やるなー
サブクラス化
いきなりソース!
のみっ!
using System;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
public class ListViewEx : ListView {
public ListViewEx() : base() {
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
this.EditBox = new TextBox();
this.EditBox.Parent = this;
this.EditBox.Visible = false;
this.EditBox.BorderStyle = BorderStyle.FixedSingle;
this.EditBox.Leave += EditBox_Leave;
this.EditBox.KeyPress += EditBox_KeyPress;
}
protected override void Dispose(bool disposing) {
if(disposing) {
this.EditBox.KeyPress -= EditBox_KeyPress;
this.EditBox.Leave -= EditBox_Leave;
this.EditBox.Dispose();
}
base.Dispose(disposing);
}
TextBox EditBox;
private void EditBox_Leave(object sender, EventArgs e) {
CurrentColumn.Text = EditBox.Text;
EditBox.Visible = false;
}
private void EditBox_KeyPress(object sender, KeyPressEventArgs e) {
switch(e.KeyChar) {
case (char)Keys.Enter:
this.Focus();
e.Handled = true;
break;
case (char)Keys.Escape:
EditBox.Text = CurrentColumn.Text;
this.Focus();
e.Handled = true;
break;
}
}
[Browsable(false)]
public ListViewItem CurrentRow { get; set; }
[Browsable(false)]
public ListViewItem.ListViewSubItem CurrentColumn { get; set; }
[Browsable(false)]
public int CurrentRowIndex { get { return (CurrentRow == null) ? -1 : CurrentRow.Index; } }
[Browsable(false)]
public int CurrentColumnIndex { get { return (CurrentColumn == null) ? -1 : CurrentRow.SubItems.IndexOf(CurrentColumn); } }
protected override void OnItemCheck(ItemCheckEventArgs ice) {
if(CurrentColumn != null && CurrentColumnIndex != 0)
ice.NewValue = ice.CurrentValue;
base.OnItemCheck(ice);
}
protected override void OnMouseDown(MouseEventArgs e) {
Point loc = this.PointToClient(Cursor.Position);
CurrentRow = null;
CurrentColumn = null;
CurrentRow = this.GetItemAt(loc.X, loc.Y);
if(CurrentRow == null || !CurrentRow.Bounds.Contains(loc))
CurrentRow = null;
else {
CurrentColumn = CurrentRow.GetSubItemAt(loc.X, loc.Y);
if(CurrentColumn == null || !CurrentColumn.Bounds.Contains(loc))
CurrentColumn = null;
}
base.OnMouseDown(e);
}
protected override void OnResize(EventArgs e) {
this.Focus();
base.OnResize(e);
}
protected override void OnColumnWidthChanging(ColumnWidthChangingEventArgs e) {
this.Focus();
base.OnColumnWidthChanging(e);
}
protected override void OnNotifyMessage(Message m) {
switch(m.Msg) {
case WM_HSCROLL:
case WM_VSCROLL:
this.Focus();
break;
}
base.OnNotifyMessage(m);
}
const int WM_HSCROLL = 0x114;
const int WM_VSCROLL = 0x115;
public void EditColumn() {
if(CurrentColumn == null || CurrentColumnIndex == 0) return;
Rectangle rect = CurrentColumn.Bounds;
rect.Intersect(this.ClientRectangle);
rect.Y -= 1;
EditBox.Bounds = rect;
EditBox.Text = CurrentColumn.Text;
EditBox.Visible = true;
EditBox.BringToFront();
EditBox.Focus();
}
}
いやいや、使用説明だけはしなくては…
使いたいプロジェクトの中に ListVIewEx.cs
のクラスファイルを追加して、上記ソースをまるっと貼り付けちゃって下さい。
一旦全体ビルドしたら、ツールボックスに ListViewEx
が増えている筈なのでデザイナ画面で使えます。(勿論ビルドエラーがあったらダメですよ)
- プロパティ
- CurrentRowとCurrentRowIndexプロパティが増えてます
- CurrentColumnとCurrentColumnIndexプロパティも増えてます
- メソッド
- EditColumn()が定義されています
機能は名前から推し量って下さい。(投げやり)
EditColumn
メソッドはフォームに張り付けた ListViewEx
の MouseDoubleClick
イベント辺りで必要性を確認の上呼びだす仕様です。
コードで説明すると、こんな感じ↓
これで前稿と同じく、カラム2だけが編集対象となります。
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e) {
if(listView1.CurrentColumnIndex == 1)
listView1.EditColumn();
}
一つ忘れものがありました。
カラムサイズを調整した時にもモード抜けないといけないですね。サブクラスバージョンでは織り込んであります。
次への布石
今回のサブクラス化では、どのカラムが編集対象であるかは、外部からコントロールしなければなりません。
カラム位置で判定していたりすると、コードの可読性は落ちますしメンテナンス性も悪くなります。
ここはひとつListViewItemのカラムヘッダ辺りに Editable
みたいなプロパティがあると良いのになー
とか思っちゃったのが運の尽き。
更に泥沼にはまっていく…
ちゅー事で次はColumnHeaderのサブクラス対応かっ?
請うご期待!
※ 一旦脳味噌クールダウン図って別ネタを挟むかも…