3

ボタンを動的に作成するとき、新しいMouseEventHandlerが必要でした。私はそうしました、

this.Controls[btnAdd.Name].MouseClick += new MouseEventHandler(generalMethods.generatePopup());

ただし、イベントにパラメーターを渡す必要があるため、ボタン番号を示す整数を受け入れるようにgeneratePopupを作成しました(さらに使用できるようにしました)。以前は、匿名のデリゲートを使用して追加のパラメーターを渡すだけでしたが、新しいインスタンスを作成したいので、これは機能しないようです。

this.Controls[btnAdd.Name].MouseClick += delegate(object sender, MouseEventArgs e) { new MouseEventHandler( generalMethods.generatePopup(sender, e, i); };

エラーは新しいMouseEventHandlerにあるようです。これを取り出すと、正常に動作し、追加のデータを渡すことができますが、新しいインスタンスではないため、各ボタンに独自のイベントを与えることはありません。

this.Controls[btnAdd.Name].MouseClick += new MouseEventHandler(generalMethods.generatePopup());

誰かがこれを回避する方法を知っていますか?たとえば、アノンデリゲートアプローチを引き続き使用し、イベントの新しいインスタンスを作成するにはどうすればよいですか?

編集:うーん、私はこれを試しました(パラメーターはうまくいくと思います)が、ボタンごとに新しいマウスイベントハンドラーを作成する代わりに、すべてのボタンに同じものを使用しているようです。正しいボタン番号を取得していますが、ポップアップのすべてのラベルは、正しいボタン番号ではなく、最後のボタン番号を返しています。何か案は?

編集2:ボタンを生成するための私のコードブロックは次のとおりです。

 for (int i = 0; i <= count && i < 2; i++)
        {

            Button btnAdd = new Button();
            btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
            btnAdd.Location = new Point(x, y);
            btnAdd.Tag = i;
            btnAdd.Name = "btn" + i.ToString();
            btnAdd.BackColor = Color.Green;

            this.Controls.Add(btnAdd);

            this.Controls[btnAdd.Name].MouseClick += (sender, e) =>
{
    int index = i;
    generalMethods.generatePopup(sender, e, index);
};

これが私のgeneratePopupメソッドです。これはmouseEventHandlerです。

public void generatePopup(object sender, MouseEventArgs e, int buttonNumber)
    {
      //  DBConnector mDBConnector = new DBConnector();
      //  DataTable dataTable = mDBConnector.Select("SELECT * FROM devices WHERE deviceID = " + buttonNumber);


        DeviceBreakdownPopup popupDevice = new DeviceBreakdownPopup();
        popupDevice.lblDeviceNo.Text = buttonNumber.ToString();

        PopupWindow popup = new PopupWindow(popupDevice);
        popup.Show(Cursor.Position);

    }

わかりやすくするために、何が起こっているのかを示した画像を次に示します。

エラーの例

ここでは、ラベル「2」が付けられた両方のポップアップユーザーコントロールが表示されていますが、それぞれに正しい値「1」と「2」が必要です。

4

7 に答える 7

2

これを試して:

this.Controls[btnAdd.Name].MouseClick += new MouseEventHandler(
    (sender, evt) => {
        generalMethods.generatePopup()
    }
);

この部分はオプションです。コンパイラーは、割り当てnew MouseEventHandler(...)の左側からパラメーター・タイプを判別します。+=

編集コードの問題は、変更されたクロージャーにアクセスすることです。から一時変数を作成しi、それをラムダ内で使用して問題を修正する必要があります。

for (int i = 0; i <= count && i < 2; i++)
    {

        Button btnAdd = new Button();
        btnAdd.Text = dataTable.Rows[i]["deviceDescription"].ToString();
        btnAdd.Location = new Point(x, y);
        btnAdd.Tag = i;
        btnAdd.Name = "btn" + i.ToString();
        btnAdd.BackColor = Color.Green;

        this.Controls.Add(btnAdd);
        var temp = i;
        this.Controls[btnAdd.Name].MouseClick += (sender, e) =>
            {
            int index = temp;
            generalMethods.generatePopup(sender, e, index);
        };
}
于 2012-05-23T14:35:16.063 に答える
1

どのタイプがgeneratePopup返されますか?すでに返された場合は、MouseEventHandler問題ないはずです(インスタンスごとに新しいハンドラーが生成される限り)。次のようなもの:

btnAdd.MouseClick += generalMethods.generatePopup();

/* in generalMethods */
private static int ButtonIndex = 0;
public MouseEventHandler generatePopup()
{
   int tempIndex = ButtonIndex++;
   return new MouseEventHandler((sender, ea) => generalMethods.generatePopup(sender, ea, tempIndex));
}

この方法で行う理由は、メソッドがボタンごとgeneratePopupに新しいものを作成するためです。MouseEventHandler生成される各ハンドラーは、作成したラムダのクロージャーを作成tempIndexし、ローカルフィールドとして設定した変数を追加します。したがって、ハンドラーが作成されると、ラムダ(tempIndexを含む)に対して新しいクロージャーが作成され、個々のボタン(tempIndexのローカルバージョン)ごとにgeneratePopupメソッドが呼び出されます。変数のクロージャはLambdaの外部で発生するため、Lambdaを指定する前にローカル変数を設定する必要があります。そうすれば、適切にキャプチャされます。

試してみて、私たちに知らせてください。

編集:ループでボタンを生成しているようです。それらが動的に生成される状況はありますか(つまり、そのループ内ではなく、最初の作成後のいつか)?もしそうなら、あなたはすでにボタン自体に関するすべての情報を持っています:

(sender, ea) => generalMethods.generatePopup(sender, ea, (int)((Control)sender).Tag)

すでにタグにインデックスを添付しているので、ボタンごとに異なるバージョンのインデックスがあることを心配する必要はありません。現在のバージョンでは、ループ変数自体(再利用される)の参照を取得しようとしているため、ループが完了するまでに、MouseEventHandlerのすべてのインスタンスが最終状態のループ変数を参照します。中間値を格納する一時変数を作成しない限り、ループ変数とラムダは混在しません。

于 2012-05-23T14:58:33.493 に答える
0

私が考えることができる唯一のことは、継承されたコントロールを作成し、独自のイベントとプロパティを追加することです。イベントは、インスタンス化されるとプロパティに入力され、トリガーされるとマウスクリックを呼び出します。

于 2012-05-23T14:36:09.900 に答える
0

標準のイベントパターンを使用します。イベントのソースを取得して、目的のタイプにキャストできます。

this.Controls[btnAdd.Name].MouseClick += new MouseEventHandler(MyControl_MouseClick);

//...

void MyControl_MouseClick(object sender, MouseEventArgs e)
{
    var button = sender as Button;

    if (button.Name == "Add") // here is how to retrieve the button name
    {
        ...
    }
}
于 2012-05-23T14:36:24.127 に答える
0

あなたはこのようにすることはできません。

デリゲート構文の後には、その特定のイベントを添付したメソッドが続きます。カスタムコントロールとそのコントロールのカスタムイベントを作成できます。

ここでは、次のようにイベントを作成する方法を説明します。

  // Define a delegate named LogHandler, which will encapsulate
    // any method that takes a string as the parameter and returns no value
       public delegate void LogHandler(string message);

    // Define an Event based on the above Delegate
       public event LogHandler Log;

これイベントとデリゲートの簡略化を参照してください。

カスタムコントロールを作成するには、次の手順に従います-Winformsでのカスタムコントロールの作成-パート1および.NETFrameworkを使用したカスタムWindowsフォームコントロールの開発

public partial class UserControl1 : TextBox
于 2012-05-23T14:36:28.867 に答える
0

これは機能するはずです:

this.Controls[btnAdd.Name].MouseClick += 
  (sender, e) => generalMethods.generatePopup(sender, e, i);

これにより、各ボタンクリックイベントによって呼び出される、一意の引数を持つ一意の匿名メソッドが作成されます。

于 2012-05-23T14:37:54.860 に答える
0

それ以外の場合はループパラメータを参照するため、内部スコープでインデックスを宣言する必要があります。

for (int i = 0; i < 42; i++)
{
    this.Controls[name].MouseClick += (sender, e) =>
    {
        int index = i;
        generalMethods.generatePopup(sender, e, index);
    }
}

ボタンごとに指定されたハンドラーは必要ありませんが(すべて1つで正常に機能します)、各ボタンに独自のインデックスオブジェクトを付与する必要があります。

于 2012-05-23T14:47:25.840 に答える