DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DataGridのLinkLabelクリック時の動作

環境/言語:[WindowsXP SP2 C# .NET Framework1.0]
分類:[.NET]

.NET C#で開発しています。
現在、以下のような処理を行わせたいと考えています。

1.Form上で、「検索」ボタンを押す。
2.DataGridに検索結果が表示される。(カラム1には、LinkLabelを表示させる。)
3.LinkLabelをクリックする。
4.クリックされた列の情報が別のFormに表示される。

問題としては、検索一回目の場合は問題ないのですが、
検索を二回以上行うと、リンクをクリックしたときに例外が発生します。
(System.ArgumentException: 列 'カラム1' はテーブル'table'に属していません)


例外をcatchして何も行わない場合、詳細情報のFormが表示されます。
例外は、検索を行った回数分だけ発生しているようです。
(クリックした際に、検索回数分、Formが呼ばれているようです。)

ソースは次のような感じです。どなたかアドバイスしていただけないでしょうか?


<Formの検索ボタンクリック時のメソッド>

private void findButton_Click(object sender, System.EventArgs e)
{
DataSet myds = new DataSet();
DataTable mytable = new DataTable();
Component1 mydb = new Component1();

// 条件にあうデータを抽出
myds = mydb.getDS(textBox1.Text);

if (myds.Tables.Count > 0)
{

DataGridTableStyle tableStyle = new DataGridTableStyle();
tableStyle.MappingName = "TABLE";

int numCols = myds.Tables["TABLE"].Columns.Count;
DataGridTextBoxColumn textboxColStyle = null;
DataGridLinkLabelColumn linkLabelColStyle = null;

for(int i = 0; i < numCols ; ++i)
{
// カラム1の場合、LinkLabelを生成
if(myds.Tables["TABLE"].Columns[i].ColumnName.Equals("カラム1"))
{
linkLabelColStyle = new DataGridLinkLabelColumn();
linkLabelColStyle.HeaderText = "カラム1";
linkLabelColStyle.MappingName =
myds.Tables["TABLE"].Columns[i].ColumnName;
tableStyle.GridColumnStyles.Add(linkLabelColStyle);
dataGrid1.MouseUp += new
MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
}
// カラム1以外
else
{
textboxColStyle = new DataGridTextBoxColumn();
textboxColStyle.HeaderText = myds.Tables["TABLE"].Columns[i].ColumnName;
textboxColStyle.MappingName =
myds.Tables["TABLE"].Columns[i].ColumnName;
tableStyle.GridColumnStyles.Add(textboxColStyle);
}

dataGrid1.TableStyles.Clear();
dataGrid1.TableStyles.Add(tableStyle);
dataGrid1.DataSource = myds.Tables["TABLE"];
dataGrid1.SetDataBinding(mytable.DefaultView, "");
}
}
}
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
<リンクラベルを表示させるクラス>
protected override void Edit(CurrencyManager source,
int rowNum,
Rectangle bounds,
bool readOnly,
string instantText,
bool cellIsVisible)
{
}


protected override void Paint( Graphics g,
Rectangle bounds,
CurrencyManager source,
int rowNum,
Brush backBrush,
Brush foreBrush,
bool alignToRight)
{
//表示する文字列を取得
string text = GetColumnValueAtRow(source, rowNum).ToString();

//書式設定
StringFormat sf = new StringFormat();
g.FillRectangle(backBrush, bounds); //背景色

Brush textBrush = Brushes.Blue; //前景色

Font textFont = new Font(DataGridTableStyle.DataGrid.Font.FontFamily,
DataGridTableStyle.DataGrid.Font.Size,
DataGridTableStyle.DataGrid.Font.Style | FontStyle.Underline);

RectangleF rectf = new RectangleF(bounds.X,
bounds.Y,
bounds.Width,
bounds.Height);
rectf.Inflate(-_margin.X, -_margin.Y);

//文字列を描画する
g.DrawString(text, textFont, textBrush, rectf, sf);

sf.Dispose();
textFont.Dispose();
}

public void DataGrid_MouseUp(object sender, MouseEventArgs e)
{
DataGrid grid = DataGridTableStyle.DataGrid;
DataGrid.HitTestInfo info = grid.HitTest(e.X, e.Y);

//マウスがセル上にあるか調べる
if (info.Type == DataGrid.HitTestType.Cell
&& info.Column == DataGridTableStyle.GridColumnStyles.IndexOf(this))
{
try
{
CurrencyManager cm =
(CurrencyManager)grid.BindingContext[grid.DataSource,grid.DataMember];
string str = GetColumnValueAtRow(cm,info.Row).ToString();
Form2 form2 = new Form2(str);
form2.Show();
}
}
}
> 検索を二回以上行うと、リンクをクリックしたときに例外が発生します。
> (System.ArgumentException: 列 'カラム1' はテーブル'table'に属していません)

デバッグした時に、どこの行で発生しているのでしょうか?
MouseUpイベントプロシージャの中ではなさそうな気がしますし・・・。

> 例外は、検索を行った回数分だけ発生しているようです。
> (クリックした際に、検索回数分、Formが呼ばれているようです。)

dataGrid1.MouseUp += new
MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);

が検索の度に実行されるからかな?
例外が発生するのは、
  string str = GetColumnValueAtRow(cm,info.Row).ToString();
です。

私も検索の度に、
  dataGrid1.MouseUp += new
  MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
が行われるためかなぁと考えたのですが、dataGridの初期化?方法がわからず
途方にくれています。。
C#初心者のため、原因追求にいきづまっています。
原因追求のためにどんなデバッグコードを仕込んだらよいでしょうか。。。
すいません、開発の初歩的な質問で・・・。
>例外が発生するのは、
>  string str = GetColumnValueAtRow(cm,info.Row).ToString();
>です。

Form2が例外が発生した場合でも表示されるということでしたので、strはきちんと取得できていると思っていましたが、そうではないんでしょうか?

>私も検索の度に、
>  dataGrid1.MouseUp += new
>  MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
>が行われるためかなぁと考えたのですが、dataGridの初期化?方法がわからず
>途方にくれています。。

とりあえずはフラグを用意して、一度上記の行を実行したらフラグを立て、次からはフラグが立っていれば実行しないようにすれば良いと思います。
もっとスマートな方法があるかと思って探そうと思っていたのですが、時間が取れず、調査できていません。
> Form2が例外が発生した場合でも表示されるということでしたので、strはきちんと取得できていると思っていましたが、そうではないんでしょうか?
>
strは1度だけ取得できています。2度検索してリンクをクリックした場合、
1回はNG、もう1回はOK、3度検索してリンクをクリックした場合は
1,2回はNG,最後の1回はOKという感じです。
ですので、例外をcatchしてスルーさせた場合、リンクをクリックした場合、
一度だけ詳細Formが起動するというようになります。(見かけ上だけで、後ろでは
例外が発生しているわけですが。。。)

>
> とりあえずはフラグを用意して、一度上記の行を実行したらフラグを立て、次からはフラグが立っていれば実行しないようにすれば良いと思います。
> もっとスマートな方法があるかと思って探そうと思っていたのですが、時間が取れず、調査できていません。
ありがとうございます。もう少しがんばってみます。
>---------------------------------------
// カラム1の場合、LinkLabelを生成
if(myds.Tables["TABLE"].Columns[i].ColumnName.Equals("カラム1"))
{
   linkLabelColStyle = new DataGridLinkLabelColumn();
   linkLabelColStyle.HeaderText = "カラム1";
   linkLabelColStyle.MappingName = 
   myds.Tables["TABLE"].Columns[i].ColumnName;
   tableStyle.GridColumnStyles.Add(linkLabelColStyle);
   dataGrid1.MouseUp += new 
   MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
}
>---------------------------------------

のところなんですが、1度目の検索はいいとして、2度目の検索の時、
linkLabelColStyleが、新しくnewされたDataGridLinkLabelColumn()で
書きつぶされてしまいます。
そうすると、1度目の、
dataGrid1.MouseUp += new 
   MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
によって指定されたイベントハンドラは宙に浮いてしまいます。
つまり、2回検索した場合には、1度目のDataGrid_MouseUpは失敗し、
2度目のDataGrid_MouseUpは成功することになります。
同様に3度検索した場合は、1、2度目のDataGrid_MouseUpは失敗し、
3度目のDataGrid_MouseUpは成功することになります。
以上のようなことが起こっているのではないでしょうか?
したがって、次のように修正したらいかがでしょうか?

// カラム1の場合、LinkLabelを生成
if(myds.Tables["TABLE"].Columns[i].ColumnName.Equals("カラム1"))
{
   linkLabelColStyle = new DataGridLinkLabelColumn();
   linkLabelColStyle.HeaderText = "カラム1";
   linkLabelColStyle.MappingName = 
   myds.Tables["TABLE"].Columns[i].ColumnName;
   tableStyle.GridColumnStyles.Add(linkLabelColStyle);
}
>---------------------------------------

Page_Loadなどで、

dataGrid1.MouseUp += new 
   MouseEventHandler(dataGrid1_MouseUp);

そして、

private void dataGrid1_MouseUp(object sender, 
                      System.Windows.Forms.MouseEventArgs e)
{
   linkLabelColStyle.DataGrid_MouseUp;
}

#フラグでイベントハンドラの登録を1回だけにするというのは
忘れてください。m(_ _)m
■No12720に返信(trapemiyaさんの記事)
> >---------------------------------------
> // カラム1の場合、LinkLabelを生成
> if(myds.Tables["TABLE"].Columns[i].ColumnName.Equals("カラム1"))
> {
> linkLabelColStyle = new DataGridLinkLabelColumn();
> linkLabelColStyle.HeaderText = "カラム1";
> linkLabelColStyle.MappingName =
> myds.Tables["TABLE"].Columns[i].ColumnName;
> tableStyle.GridColumnStyles.Add(linkLabelColStyle);
> dataGrid1.MouseUp += new
> MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
> }
> >---------------------------------------
>
> のところなんですが、1度目の検索はいいとして、2度目の検索の時、
> linkLabelColStyleが、新しくnewされたDataGridLinkLabelColumn()で
> 書きつぶされてしまいます。
> そうすると、1度目の、
> dataGrid1.MouseUp += new
> MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
> によって指定されたイベントハンドラは宙に浮いてしまいます。
> つまり、2回検索した場合には、1度目のDataGrid_MouseUpは失敗し、
> 2度目のDataGrid_MouseUpは成功することになります。
> 同様に3度検索した場合は、1、2度目のDataGrid_MouseUpは失敗し、
> 3度目のDataGrid_MouseUpは成功することになります。
> 以上のようなことが起こっているのではないでしょうか?
> したがって、次のように修正したらいかがでしょうか?
>
> // カラム1の場合、LinkLabelを生成
> if(myds.Tables["TABLE"].Columns[i].ColumnName.Equals("カラム1"))
> {
> linkLabelColStyle = new DataGridLinkLabelColumn();
> linkLabelColStyle.HeaderText = "カラム1";
> linkLabelColStyle.MappingName =
> myds.Tables["TABLE"].Columns[i].ColumnName;
> tableStyle.GridColumnStyles.Add(linkLabelColStyle);
> }
> >---------------------------------------
>
> Page_Loadなどで、
>
> dataGrid1.MouseUp += new
> MouseEventHandler(dataGrid1_MouseUp);
>
> そして、
>
> private void dataGrid1_MouseUp(object sender,
> System.Windows.Forms.MouseEventArgs e)
> {
> linkLabelColStyle.DataGrid_MouseUp;
> }
>
> #フラグでイベントハンドラの登録を1回だけにするというのは
> 忘れてください。m(_ _)m

ありがとうございます!
こういうやり方もあるんですね。
会社でしか試せないので、月曜日にやってみます。
次のように修正してみました。。
-----------------------------------------------------------
if(myds.Tables[tableName].Columns[i].ColumnName.Equals("ユーザID"))
{
DataGridLinkLabelColumn linkLabelColStyle = new DataGridLinkLabelColumn();
linkLabelColStyle.HeaderText = myds.Tables[tableName].Columns[i].ColumnName;
linkLabelColStyle.MappingName = myds.Tables[tableName].Columns[i].ColumnName;
tableStyle.GridColumnStyles.Add(linkLabelColStyle);
//dataGrid1.MouseUp += new MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
}

次のメソッドを追加。
private void Form5_Load(object sender, System.EventArgs e)
{
dataGrid1.MouseUp += new MouseEventHandler(dataGrid1_MouseUp);
}


private void dataGrid1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
DataGridLinkLabelColumn linkLabelColStyle = new DataGridLinkLabelColumn();
linkLabelColStyle.DataGrid_MouseUp(sender,e);
}

これだと、リンクが有効にならずクリックしても詳細Formが表示されませんでした。泥沼にはまりそうです。。。
> 次のメソッドを追加。
> private void Form5_Load(object sender, System.EventArgs e)
> {
> dataGrid1.MouseUp += new MouseEventHandler(dataGrid1_MouseUp);
> }
>
すいません、Formの名前が間違ってました。リンクは有効になったのですが、
現象(検索を2度以上実行すると、System.ArgumentExceptionが発生する)に
変わりありませんでした。
linkLabelColStyleをクラスの中全体で見えるスコープの位置に定義し、
以下のようにしてはどうでしょう?(未確認)

DataGridLinkLabelColumn linkLabelColStyle;

if(myds.Tables[tableName].Columns[i].ColumnName.Equals("ユーザID"))
{
   linkLabelColStyle = new DataGridLinkLabelColumn();
   linkLabelColStyle.HeaderText = myds.Tables[tableName].Columns[i].ColumnName;
   linkLabelColStyle.MappingName = myds.Tables[tableName].Columns[i].ColumnName;
   tableStyle.GridColumnStyles.Add(linkLabelColStyle);
   //dataGrid1.MouseUp += new MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp); 
}

次のメソッドを追加。
private void Form5_Load(object sender, System.EventArgs e)
{
   dataGrid1.MouseUp += new MouseEventHandler(dataGrid1_MouseUp);
}

private void dataGrid1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
   linkLabelColStyle.DataGrid_MouseUp(sender,e);
}
■No12746に返信(trapemiyaさんの記事)
> linkLabelColStyleをクラスの中全体で見えるスコープの位置に定義し、
> 以下のようにしてはどうでしょう?(未確認)
>
> DataGridLinkLabelColumn linkLabelColStyle;
>
> if(myds.Tables[tableName].Columns[i].ColumnName.Equals("ユーザID"))
> {
> linkLabelColStyle = new DataGridLinkLabelColumn();
> linkLabelColStyle.HeaderText = myds.Tables[tableName].Columns[i].ColumnName;
> linkLabelColStyle.MappingName = myds.Tables[tableName].Columns[i].ColumnName;
> tableStyle.GridColumnStyles.Add(linkLabelColStyle);
> //dataGrid1.MouseUp += new MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
> }
>
> 次のメソッドを追加。
> private void Form5_Load(object sender, System.EventArgs e)
> {
> dataGrid1.MouseUp += new MouseEventHandler(dataGrid1_MouseUp);
> }
>
> private void dataGrid1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
> {
> linkLabelColStyle.DataGrid_MouseUp(sender,e);
> }
残念ながらNGでした。
> //dataGrid1.MouseUp += new MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
のようにコメントしてしまうとリンクが有効になりません。
(前回の返信は誤りでした。Formの名前ミスではなく、コメントし忘れてました。すいません。)
初回投稿時のソースの、

dataGrid1.TableStyles.Clear();
dataGrid1.TableStyles.Add(tableStyle);
dataGrid1.DataSource = myds.Tables["TABLE"];
dataGrid1.SetDataBinding(mytable.DefaultView, "");

のところで、
//dataGrid1.TableStyles.Clear();をコメントにすると、
dataGrid1.TableStyles.Add(tableStyle);で、以下の例外が発生します。

----------------------------
'System.ArgumentException' のハンドルされていない例外が system.windows.forms.dll で発生しました。

追加情報 : このデータ グリッドのテーブル スタイル コレクションには既に同じマップ名のテーブル スタイルが含まれています。
-----------------------------

この例外をcatchして何も処理をしないで、リンクをクリックすると
詳細Formが検索の回数分だけ、表示されるようになりました。

何かをクリア(初期化)すればよいと思うのですが。。。
何とか解決できました。

private DataGridLinkLabelColumn linkLabelColStyle = new DataGridLinkLabelColumn();

をクラスレベルで宣言し、findButton_Click内の最初に、
dataGrid1.MouseUp -= new MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
を追加しました。

trapemiyaさま、ありがとうございました。
trapemiyaさまのアドバイスがなかったら解決できなかったと思います。
重ねて御礼申し上げます。
ありがとうございました。
とりあえずは動いたようでよかったです。

ただ、

> をクラスレベルで宣言し、findButton_Click内の最初に、
> dataGrid1.MouseUp -= new MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
> を追加しました。

が気になります。これを実行しなければならないということは、これ以前にイベントハンドラが2回登録されていることになります。
その辺りを確認してみてください。本来なら、ここでイベントハンドラを外す必要はないはずです。
■No12759に返信(trapemiyaさんの記事)
> とりあえずは動いたようでよかったです。
>
> ただ、
>
>>をクラスレベルで宣言し、findButton_Click内の最初に、
>>dataGrid1.MouseUp -= new MouseEventHandler(linkLabelColStyle.DataGrid_MouseUp);
>>を追加しました。
>
> が気になります。これを実行しなければならないということは、これ以前にイベントハンドラが2回登録されていることになります。
> その辺りを確認してみてください。本来なら、ここでイベントハンドラを外す必要はないはずです。

アドバイスありがとうございます!
ご指摘の箇所を再度確認してみます。
(コードレビューで突っ込まれそうですので・・・)
とりあえず、解決済みとさせていただきます。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板