.NETプログラミング研究 第34号 †
お知らせ †
過去に発行した「.NETプログラミング研究」のタイトルの一覧を閲覧できるようにしてほしいというご要望があったため、以下のURLから閲覧できるようにしました。
バックナンバーのメニュー部分を切り出して列挙して表示しているだけのものですが、ご利用いただければ幸いです。
.NET質問箱 †
「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、Q&A形式にまとめて紹介します。
文字列の計算式の計算結果を取得するには? †
【質問】
例えば、"(1+6)*5/(7-4)"のような計算式を表す文字列から、その計算結果を取得するにはどのようにすればよいのでしょうか?
【回答】
これには、いろいろな方法が考えられます。
正攻法で行けば、計算式を解析し、計算するコードを自分で書くということになります。そのために参考になりそうなコードが、例えば、「The Code Project」で紹介されている「A Math Expression Evaluator」です。この「A Math Expression Evaluator」は簡単な計算はもちろん、cos、sin、logなどにも対応しています。(ただし、コードはVB.NETのみです。)
さらに、掲示板でArAyさんが紹介されたMSDN Japanの「アルゴリズム入門:第1章 Visual C# による文字列処理入門」も参考になります。
このように自分でコードを書く以外の方法も様々あります。
まず、JScript.NETのEvalを使う方法があります。この方法は、GotDotNet Message Boardsの「String to Numeric」のスレッドでenderminhさんが紹介しています。
この方法によると、まず参照に「Microsoft.Jscript」と「Microsoft.Vsa」を追加し、次のようなコードにより、計算を実行します。
1
2
3
4
5
6
7
8
9
10
| | Dim exp As String = "(1+6)*5/(7-4)"
Dim ve As Microsoft.JScript.Vsa.VsaEngine = _
Microsoft.JScript.Vsa.VsaEngine.CreateEngine()
Dim result As Double = _
CDbl(Microsoft.JScript.Eval.JScriptEvaluate(exp, ve))
Console.WriteLine(result)
|
1
2
3
4
5
6
7
8
9
10
11
| | string exp = "(1+6)*5/(7-4)";
Microsoft.JScript.Vsa.VsaEngine ve =
Microsoft.JScript.Vsa.VsaEngine.CreateEngine();
double result =
(double) Microsoft.JScript.Eval.JScriptEvaluate(
exp, ve);
Console.WriteLine(result);
|
また、JScriptCodeProviderにより、Evalメソッドを実行する方法が「An Eval Function for C# using JScript.NET (JavaScript)」に紹介されています。
この方法によると、次のようなコードがかけます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| |
Dim exp As String = "(1+6)*5/(7-4)"
Dim [source] As String = _
"package Evaluator {" + vbCrLf + _
"class Evaluator {" + vbCrLf + _
"public function Eval(expr : String) : String {" + vbCrLf + _
"return eval(expr);} } }"
Dim cp = New Microsoft.JScript.JScriptCodeProvider
Dim icc As ICodeCompiler = cp.CreateCompiler()
Dim cps As New CompilerParameters
Dim cres As CompilerResults
cps.GenerateInMemory = True
cres = icc.CompileAssemblyFromSource(cps, [source])
Dim asm As [Assembly] = cres.CompiledAssembly
Dim t As Type = asm.GetType("Evaluator.Evaluator")
Dim eval As Object = Activator.CreateInstance(t)
Dim result As String = CStr(t.InvokeMember("Eval", _
BindingFlags.InvokeMethod, Nothing, eval, New Object() {exp}))
Console.WriteLine(result)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| |
string exp = "(1+6)*5/(7-4)";
string source =
@"package Evaluator
{
class Evaluator
{
public function Eval(expr : String) : String
{
return eval(expr);
}
}
}";
CodeDomProvider cp = new Microsoft.JScript.JScriptCodeProvider();
ICodeCompiler icc = cp.CreateCompiler();
CompilerParameters cps = new CompilerParameters();
CompilerResults cres;
cps.GenerateInMemory = true;
cres = icc.CompileAssemblyFromSource(cps, source);
Assembly asm = cres.CompiledAssembly;
Type t = asm.GetType("Evaluator.Evaluator");
object eval = Activator.CreateInstance(t);
string result = (string) t.InvokeMember("Eval",
BindingFlags.InvokeMethod,
null,
eval,
new object[] {exp});
Console.WriteLine(result);
|
さらに、掲示板でピラルクさんが提案されたように、CSharpCodeProviderを使って、計算式が含まれるコードの文字列をコンパイルし、実行する方法もあります。この方法は「The Code Project」などでもいくつか紹介されています。
具体的なコードは、例えば、次のようなものです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| |
Dim [source] As String = _
"public class MainClass {" + vbCrLf + _
"public static double EVal() {" + vbCrLf + _
"return (1d+6d)*5d/(7d-4d);" + vbCrLf + _
"} }"
Dim cp = New Microsoft.CSharp.CSharpCodeProvider
Dim icc As ICodeCompiler = cp.CreateCompiler()
Dim cps As New CompilerParameters
Dim cres As CompilerResults
cps.GenerateInMemory = True
cres = icc.CompileAssemblyFromSource(cps, [source])
Dim asm As [Assembly] = cres.CompiledAssembly
Dim t As Type = asm.GetType("MainClass")
Dim d As Double = CDbl(t.InvokeMember("EVal", _
BindingFlags.InvokeMethod, Nothing, Nothing, Nothing))
Console.WriteLine(d)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| |
string source = @"
public class MainClass
{
public static double EVal()
{
return (1d+6d)*5d/(7d-4d);
}
}";
CodeDomProvider cp = new Microsoft.CSharp.CSharpCodeProvider();
ICodeCompiler icc = cp.CreateCompiler();
CompilerParameters cps = new CompilerParameters();
CompilerResults cres;
cps.GenerateInMemory = true;
cres = icc.CompileAssemblyFromSource(cps, source);
Assembly asm = cres.CompiledAssembly;
Type t = asm.GetType("MainClass");
double d = (double) t.InvokeMember("EVal",
BindingFlags.InvokeMethod,
null,
null,
null);
Console.WriteLine(d);
|
前のJScriptCodeProviderを使った方法と比べると、この方法は計算式をコードに含めなければならず、計算式が変わるたびにコンパイルが必要になりますし、メモリのアセンブリをどのように解放するかという問題もあります(*1)。そのため、実用としては困難かもしれません。
(*1)この問題に関しては、次のページに詳しいです。
Microsoft Script Controlが使用できるならば、VBScriptやJSCriptのEval関数を使う方法もあります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| | Dim exp As String = "(1+6)*5/(7-4)"
Dim t As Type = _
Type.GetTypeFromProgID("MSScriptControl.ScriptControl")
Dim obj As Object = Activator.CreateInstance(t)
t.InvokeMember("Language", _
System.Reflection.BindingFlags.SetProperty, _
Nothing, _
obj, _
New Object() {"vbscript"})
Dim result As Double = CDbl( _
t.InvokeMember("Eval", _
System.Reflection.BindingFlags.InvokeMethod, _
Nothing, _
obj, _
New Object() {exp}))
Console.WriteLine(result)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| | string exp = "(1+6)*5/(7-4)";
Type t = Type.GetTypeFromProgID("MSScriptControl.ScriptControl");
object obj = Activator.CreateInstance(t);
t.InvokeMember("Language",
System.Reflection.BindingFlags.SetProperty,
null,
obj,
new object[] {"vbscript"});
double result = (double) t.InvokeMember("Eval",
System.Reflection.BindingFlags.InvokeMethod,
null,
obj,
new object[] {exp});
Console.WriteLine(result);
|
これ以外にも、DataTable.Computeメソッドを使う方法など、まだまだありそうですが、きりが無いので、この辺で終わりにします。(面白い方法がありましたら、ご連絡ください。)
○この記事の基になった掲示板のスレッド
TabControlのTabPageを非表示にするには? †
【質問】
TabControlのTabPageにはVisibleプロパティが見つかりません。TabPageを非表示にするにはどのようにすればよいのでしょうか?
【回答】
TabPageを非表示にするには、TabControl.TabPagesプロパティのRemoveまたはRemoveAtメソッドを使って削除するしかないようです。よって一時的にTabPageを非表示にするには、非表示にするTabPageオブジェクトを保持しておき、Removeメソッドで削除し、再び表示するときは、TabControl.TabPagesプロパティのAddメソッドで追加します。
TabControlのTabPageを隠し、再び表示させるためのコードを以下に示します。まずは、次のようなTabPageManagerクラスを書きます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| | Public Class TabPageManager
Private Class TabPageInfo
Public TabPage As TabPage
Public Visible As Boolean
Public Sub New(ByVal page As TabPage, ByVal v As Boolean)
TabPage = page
Visible = v
End Sub
End Class
Private _tabPageInfos As TabPageInfo() = Nothing
Private _tabControl As TabControl = Nothing
Public Sub New(ByVal crl As TabControl)
_tabControl = crl
_tabPageInfos = _
New TabPageInfo(_tabControl.TabPages.Count - 1) {}
Dim i As Integer
For i = 0 To _tabControl.TabPages.Count - 1
_tabPageInfos(i) = _
New TabPageInfo(_tabControl.TabPages(i), True)
Next i
End Sub
Public Sub ChangeTabPageVisible( _
ByVal index As Integer, ByVal v As Boolean)
If _tabPageInfos(index).Visible = v Then
Return
End If
_tabPageInfos(index).Visible = v
_tabControl.SuspendLayout()
_tabControl.TabPages.Clear()
Dim i As Integer
For i = 0 To _tabPageInfos.Length - 1
If _tabPageInfos(i).Visible Then
_tabControl.TabPages.Add(_tabPageInfos(i).TabPage)
End If
Next i
_tabControl.ResumeLayout()
End Sub
End Class
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| | public class TabPageManager
{
private class TabPageInfo
{
public TabPage TabPage;
public bool Visible;
public TabPageInfo(TabPage page, bool v)
{
TabPage = page;
Visible = v;
}
}
private TabPageInfo[] _tabPageInfos = null;
private TabControl _tabControl = null;
public TabPageManager(TabControl crl)
{
_tabControl = crl;
_tabPageInfos = new TabPageInfo[_tabControl.TabPages.Count];
for(int i = 0; i < _tabControl.TabPages.Count; i++)
_tabPageInfos[i] =
new TabPageInfo(_tabControl.TabPages[i], true);
}
public void ChangeTabPageVisible(int index, bool v)
{
if (_tabPageInfos[index].Visible == v)
return;
_tabPageInfos[index].Visible = v;
_tabControl.SuspendLayout();
_tabControl.TabPages.Clear();
for(int i = 0; i < _tabPageInfos.Length; i++)
{
if (_tabPageInfos[i].Visible)
_tabControl.TabPages.Add(_tabPageInfos[i].TabPage);
}
_tabControl.ResumeLayout();
}
}
|
次に、このTabPageManagerクラスを使ってTabControlのTabPageを隠し、再び表示させるコードを示します。フォーム(Form1)にTabControl(TabControl1)が配置されており、TabControl1にいくつかのTabPageが追加されている時、Button1のクリックによりTabControl1の一番先頭のTabPageを隠し、さらに、Button2のクリックにより再びこのTabPageを表示させるようにしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| | Private _tabPageManager As TabPageManager
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles MyBase.Load
_tabPageManager = New TabPageManager(TabControl1)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
_tabPageManager.ChangeTabPageVisible(0, False)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
_tabPageManager.ChangeTabPageVisible(0, True)
End Sub
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| | TabPageManager _tabPageManager = null
private void Form1_Load(object sender, System.EventArgs e)
{
_tabPageManager = new TabPageManager(TabControl1);
}
private void Button1_Click(object sender, System.EventArgs e)
{
_tabPageManager.ChangeTabPageVisible(0, false);
}
private void button2_Click(object sender, System.EventArgs e)
{
_tabPageManager.ChangeTabPageVisible(0, true);
}
|
○この記事の基になった掲示板のスレッド
DataGridで複数行選択できないようにし、セルがアクティブにならならず、行全体が選択されるようにするには? †
【質問】
Windowsアプリケーションにおいて、ListViewコントロールのMultiSelectプロパティをFalseにした時のように、DataGridコントロールで複数行選択することができなく、さらに、セルをクリックした時にセルがアクティブになることなく、そのセルの行全体が選択されるようにしたいのですが、どのようにすればよいでしょうか?
【回答】
まず、DataGridで一つの行だけを選択できるようにする方法を考えてみましょう。これに関しては、「Windows Forms FAQ」の「How can I make my DataGrid support a single select mode, and not the default multiselect mode?」や「TheScarms .NET Code Library」の「Make the DataGrid support single select vs multiselect mode.」でその方法が紹介されています。
これらで紹介されている方法は、DataGridクラスのOnMouseMoveをオーバーライドして、マウスドラッグによる選択が無効になるようにし、さらにOnMouseDownをオーバーライドして、前に選択した行の選択を取り消すという方法です。
しかしこのやり方では、キーボードによる複数行の選択を全く考慮しておらず、不完全です。(マウスの部分も不完全な点が多々ありますが。)
そこで以下に示すコードでは、OnMouseMoveとOnMouseDownをオーバーライドする以外に、ProcessCmdKeyをオーバーライドして、Shiftキーと上矢印または下矢印キーが押された時、ShiftキーとCtrlキーとHomeまたはEndキーが押された時、CtrlキーとAキーが押された時のそれぞれの場合を無効にしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
| | Imports System
Imports System.Drawing
Imports System.Windows.Forms
Namespace Dobon.Samples.Forms
Public Class MyDataGrid
Inherits DataGrid
Private lastRowSelected As Integer = -1
Private rowSelecting As Boolean = False
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
If rowSelecting = False Or _
(e.Button And MouseButtons.Left) <> MouseButtons.Left Then
MyBase.OnMouseMove(e)
End If
End Sub
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
rowSelecting = False
Dim info As HitTestInfo = Me.HitTest(e.X, e.Y)
If info.Type = HitTestType.Cell Or _
info.Type = HitTestType.RowHeader Then
If lastRowSelected <> -1 Then
Dim cm As CurrencyManager = _
CType(BindingContext(DataSource), _
CurrencyManager)
If lastRowSelected < cm.Count Then
Me.UnSelect(lastRowSelected)
Else
Me.ResetSelection()
End If
End If
If info.Type = HitTestType.Cell Then
lastRowSelected = -1
MyBase.OnMouseDown(e)
Else If info.Type = HitTestType.RowHeader Then
If (Control.ModifierKeys And Keys.Shift) = 0 Then
MyBase.OnMouseDown(e)
Else
CurrentCell = _
New DataGridCell(info.Row, info.Column)
End If
Me.Select(info.Row)
lastRowSelected = info.Row
rowSelecting = True
End If
Else
MyBase.OnMouseDown(e)
End If
End Sub
Protected Overrides Function ProcessCmdKey( _
ByRef msg As Message, ByVal keyData As Keys) As Boolean
Const WM_KEYDOWN As Integer = &H100
Const WM_KEYUP As Integer = &H101
If msg.Msg = WM_KEYDOWN Or msg.Msg = WM_KEYUP Then
Dim keyCode As Keys = _
CType(CInt(keyData), Keys) And Keys.KeyCode
If (keyData And Keys.Shift) = Keys.Shift And _
(keyCode = Keys.Up Or keyCode = Keys.Down) Then
Return True
End If If (keyData And Keys.Shift) = Keys.Shift And _
(keyData And Keys.Control) = Keys.Control And _
(keyCode = Keys.Home Or keyCode = Keys.End) Then
Return True
End If
If (keyData And Keys.Control) = Keys.Control And _
keyCode = Keys.A Then
Return True
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
End Class
End Namespace
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
| | using System;
using System.Drawing;
using System.Windows.Forms;
namespace Dobon.Samples.Forms
{
public class MyDataGrid : DataGrid
{
private int lastRowSelected = -1;
private bool rowSelecting = false;
protected override void OnMouseMove(MouseEventArgs e)
{
if (rowSelecting == false || _
(e.Button & MouseButtons.Left) != MouseButtons.Left)
base.OnMouseMove(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
rowSelecting = false;
HitTestInfo info = this.HitTest(e.X, e.Y);
if (info.Type == HitTestType.Cell ||
info.Type == HitTestType.RowHeader)
{
if (lastRowSelected != -1)
{
CurrencyManager cm =
(CurrencyManager) BindingContext[DataSource];
if (lastRowSelected < cm.Count)
this.UnSelect(lastRowSelected);
else
this.ResetSelection();
}
if (info.Type == HitTestType.Cell)
{
lastRowSelected = -1;
base.OnMouseDown(e);
}
else if (info.Type == HitTestType.RowHeader)
{
if ((Control.ModifierKeys & Keys.Shift) == 0)
base.OnMouseDown(e);
else
CurrentCell =
new DataGridCell(info.Row, info.Column);
this.Select(info.Row);
lastRowSelected = info.Row;
rowSelecting = true;
}
}
else
{
base.OnMouseDown(e);
}
}
protected override bool ProcessCmdKey(
ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
if (msg.Msg == WM_KEYDOWN || msg.Msg == WM_KEYUP)
{
Keys keyCode = (Keys)(int)keyData & Keys.KeyCode;
if ((keyData & Keys.Shift) == Keys.Shift &&
(keyCode == Keys.Up || keyCode == Keys.Down))
return true;
if ((keyData & Keys.Shift) == Keys.Shift &&
(keyData & Keys.Control) == Keys.Control &&
(keyCode == Keys.Home || keyCode == Keys.End))
return true;
if ((keyData & Keys.Control) == Keys.Control &&
keyCode == Keys.A)
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
}
|
次にセルがアクティブにならないようにする方法を考えます。この方法も、「Windows Forms FAQ」で紹介されています。
「5.41」は、GridColumnStyleを使い、GridColumnStyleのEditメソッドをオーバーライドし、編集できないようにする方法です。「5.83」は、GridColumnStyleを使わずに、DataGrid.Controlsからスクロールバー以外のコントロールを削除するという方法です。
ここでは、「5.83」の方法を採用し、DataGridのOnControlAddedメソッドをオーバーライドして、スクロールバー以外のコントロールが追加された時は、これを削除するようにします。(ただしこの方法ではDataGridBoolColumnによるチェックボックスはアクティブになってしまうようです。)
1
2
3
4
5
6
7
8
| | Protected Overrides Sub OnControlAdded( _
ByVal e As ControlEventArgs)
MyBase.OnControlAdded(e)
If Not TypeOf e.Control Is VScrollBar And _
Not TypeOf e.Control Is HScrollBar Then
Me.Controls.Remove(e.Control)
End If
End Sub
|
1
2
3
4
5
6
| | protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (!(e.Control is VScrollBar) && !(e.Control is HScrollBar))
this.Controls.Remove(e.Control);
}
|
セルをクリックした時に行全体が選択されるようにするには、これまた「Windows Forms FAQ」にあるように、DataGridのMouseUpイベントで行を選択するようにすればよいでしょう。
クリックでも行が選択されるようにするには、CurrentCellChangedイベントなど、適当なイベントを使ってください。ここでは、OnMouseDownメソッドで行を選択するようにします。
以上の考察により書かれたDataGridクラスの派生クラス(MyDataGridクラス)のコードを以下に示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
| | Imports System
Imports System.Drawing
Imports System.Windows.Forms
Namespace Dobon.Samples.Forms
Public Class MyDataGrid
Inherits DataGrid
Private lastRowSelected As Integer = -1
Private rowSelecting As Boolean = False
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
If rowSelecting = False Or _
(e.Button And MouseButtons.Left) <> MouseButtons.Left Then
MyBase.OnMouseMove(e)
End If
End Sub
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
rowSelecting = False
Dim info As HitTestInfo = Me.HitTest(e.X, e.Y)
If info.Type = HitTestType.Cell Or _
info.Type = HitTestType.RowHeader Then
If lastRowSelected <> -1 Then
Dim cm As CurrencyManager = _
CType(BindingContext(DataSource), _
CurrencyManager)
If lastRowSelected < cm.Count Then
Me.UnSelect(lastRowSelected)
Else
Me.ResetSelection()
End If
End If
If info.Type = HitTestType.Cell Then
lastRowSelected = -1
MyBase.OnMouseDown(e)
Me.Select(info.Row)
Else If info.Type = HitTestType.RowHeader Then
If (Control.ModifierKeys And Keys.Shift) = 0 Then
MyBase.OnMouseDown(e)
Else
CurrentCell = _
New DataGridCell(info.Row, info.Column)
End If
Me.Select(info.Row)
lastRowSelected = info.Row
rowSelecting = True
End If
Else
MyBase.OnMouseDown(e)
End If
End Sub
Protected Overrides Function ProcessCmdKey( _
ByRef msg As Message, ByVal keyData As Keys) As Boolean
Const WM_KEYDOWN As Integer = &H100
Const WM_KEYUP As Integer = &H101
If msg.Msg = WM_KEYDOWN Or msg.Msg = WM_KEYUP Then
Dim keyCode As Keys = _
CType(CInt(keyData), Keys) And Keys.KeyCode
If (keyData And Keys.Shift) = Keys.Shift And _
(keyCode = Keys.Up Or keyCode = Keys.Down) Then
Return True
End If
If (keyData And Keys.Shift) = Keys.Shift And _
(keyData And Keys.Control) = Keys.Control And _
(keyCode = Keys.Home Or keyCode = Keys.End) Then
Return True
End If
If (keyData And Keys.Control) = Keys.Control And _
keyCode = Keys.A Then
Return True
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
Protected Overrides Sub OnControlAdded( _
ByVal e As ControlEventArgs)
MyBase.OnControlAdded(e)
If Not TypeOf e.Control Is VScrollBar And _
Not TypeOf e.Control Is HScrollBar Then
Me.Controls.Remove(e.Control)
End If
End Sub
End Class
End Namespace
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
| | using System;
using System.Drawing;
using System.Windows.Forms;
namespace Dobon.Samples.Forms
{
public class MyDataGrid : DataGrid
{
private int lastRowSelected = -1;
private bool rowSelecting = false;
protected override void OnMouseMove(MouseEventArgs e)
{
if (rowSelecting == false || _
(e.Button & MouseButtons.Left) != MouseButtons.Left)
base.OnMouseMove(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
rowSelecting = false;
HitTestInfo info = this.HitTest(e.X, e.Y);
if (info.Type == HitTestType.Cell ||
info.Type == HitTestType.RowHeader)
{
if (lastRowSelected != -1)
{
CurrencyManager cm =
(CurrencyManager) BindingContext[DataSource];
if (lastRowSelected < cm.Count)
this.UnSelect(lastRowSelected);
else
this.ResetSelection();
}
if (info.Type == HitTestType.Cell)
{
lastRowSelected = -1;
base.OnMouseDown(e);
this.Select(info.Row);
}
else if (info.Type == HitTestType.RowHeader)
{
if ((Control.ModifierKeys & Keys.Shift) == 0)
base.OnMouseDown(e);
else
CurrentCell =
new DataGridCell(info.Row, info.Column);
this.Select(info.Row);
lastRowSelected = info.Row;
rowSelecting = true;
}
}
else
{
base.OnMouseDown(e);
}
}
protected override bool ProcessCmdKey(
ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
if (msg.Msg == WM_KEYDOWN || msg.Msg == WM_KEYUP)
{
Keys keyCode = (Keys)(int)keyData & Keys.KeyCode;
if ((keyData & Keys.Shift) == Keys.Shift &&
(keyCode == Keys.Up || keyCode == Keys.Down))
return true;
if ((keyData & Keys.Shift) == Keys.Shift &&
(keyData & Keys.Control) == Keys.Control &&
(keyCode == Keys.Home || keyCode == Keys.End))
return true;
if ((keyData & Keys.Control) == Keys.Control &&
keyCode == Keys.A)
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (!(e.Control is VScrollBar) &&
!(e.Control is HScrollBar))
this.Controls.Remove(e.Control);
}
}
}
|
○この記事の基になった掲示板のスレッド
コメント †