-3

次のコードを実行すると、label1コントロールが 1 回読み込まれます。その後、label1コントロールは他に何もしません。label1マウス入力イベントでコントロールを変更するにはどうすればよいですか。コード例を提供してください。

    int currentXposition, currentYposition;
    const string positionLabel = "Current Position: ";

    private void Test_Load(object sender, EventArgs a)
    {
        var temp=Color.Transparent;    //Used to store the old color name of the panels before mouse events
        var colorName = Color.Red;      //Color used to highlight panel when mouse over
        int numBlocks = 8;             //Used to hold the number of blocks per row
        int blockSize=70;

        //Initialize new array of Panels  new
        string[,] Position = new string[8, 8];
        Panel[,] chessBoardPanels = new Panel[numBlocks, numBlocks];
        string Alphabet = "A,B,C,D,E,F,G,H";
        string Numbers ="1,2,3,4,5,6,7,8";
        string[] alphaStrings = Alphabet.Split(',');
        string[] numStrings=Numbers.Split(',');
        // b = sub[0];
        int FirstValue, SecondValue;

        //Store Position Values
        for (int firstValue = 0; firstValue < 8; ++firstValue)
        {
            FirstValue = Alphabet[firstValue];
            for (int SecValue = 0; SecValue < 8; ++SecValue)
            {
                SecondValue = Numbers[SecValue];
                Position[firstValue, SecValue] = alphaStrings[firstValue] + numStrings[SecValue];
            }
        }

        //Loop to create panels
        for (int iRow = 0; iRow < numBlocks; iRow++)
        {
            for (int iColumn = 0; iColumn < numBlocks; iColumn++)
            {
                Panel p = new Panel();
                //set size
                p.Size = new Size(blockSize, blockSize);
                //set back colour
                p.BackColor = (iRow + (iColumn % 2)) % 2 == 0 ? Color.Black : Color.White;
                //set location
                p.Location = new Point(blockSize *iRow+15, blockSize * iColumn+15);
                chessBoardPanels[iRow, iColumn] = p;
                chessBoardPanels[iRow,iColumn].MouseEnter += (s,e) =>
                {
                    currentXposition = iRow;
                    currentYposition = iColumn;

                    var oldColor = (s as Panel).BackColor;
                    (s as Panel).BackColor = colorName;
                    temp = oldColor;
                    label1.Text = Position[iRow, iColumn];
                };

                chessBoardPanels[iRow, iColumn].MouseLeave += (s, e) => {
                    (s as Panel).BackColor = temp;
                };
                groupBox1.Controls.Add(p);
            }
        }
    }
4

1 に答える 1

0

スコープが混乱したときに何が起こるかを示すことが重要だと思うからです。問題が発生している理由は、変数のスコープです。ラベルはiRow * iColumn時間を変更していますが、最初の実行中のみです。それ以降、iRowiColumnは最終値に固定されます。

目的の最終目標を達成するには、Panel の拡張機能を作成するのが最も簡単です。

public class ChessPanel : Panel {

     private const Color HighlightColor = Color.Red;


     public int iColumn { get; set; }
     public int iRow { get; set; }
     public Color PrimaryColor { get; set; }

     public ChessPanel() : base()
     {
        this.MouseEnter += (s,e) =>
                {
                    this.PrimaryColor = this.BackColor;
                    this.BackColor = HighlightColor;
                };

         this.MouseLeave += (s,e) => 
                {
                    this.BackColor = this.PrimaryColor;
                };
     }     

}    

これにより、次のようにコードを削減できます。

int currentXposition, currentYposition;
const string positionLabel = "Current Position: ";

private void Test_Load(object sender, EventArgs a)
{
    var temp=Color.Transparent;    //Used to store the old color name of the panels before mouse events
    var colorName = Color.Red;      //Color used to highlight panel when mouse over
    int numBlocks = 8;             //Used to hold the number of blocks per row
    int blockSize=70;

    //Initialize new array of Panels  new
    string[,] Position = new string[8, 8];
    ChessPanel[,] chessBoardPanels = new ChessPanel[numBlocks, numBlocks];
    string Alphabet = "A,B,C,D,E,F,G,H";
    string Numbers ="1,2,3,4,5,6,7,8";
    string[] alphaStrings = Alphabet.Split(',');
    string[] numStrings=Numbers.Split(',');
    int FirstValue, SecondValue;

    //Store Position Values --- no idea what this is supposed to do...
    for (int firstValue = 0; firstValue < 8; ++firstValue)
    {
        FirstValue = Alphabet[firstValue];
        for (int SecValue = 0; SecValue < 8; ++SecValue)
        {
            SecondValue = Numbers[SecValue];
            Position[firstValue, SecValue] = alphaStrings[firstValue] + numStrings[SecValue];
        }
    }

    //Loop to create panels
    for (int iRow = 0; iRow < numBlocks; iRow++)
    {
        for (int iColumn = 0; iColumn < numBlocks; iColumn++)
        {
            ChessPanel p = new ChessPanel();
            //set size
            p.Size = new Size(blockSize, blockSize);
            //set back colour
            p.BackColor = (iRow + (iColumn % 2)) % 2 == 0 ? Color.Black : Color.White;
            //set location
            p.Location = new Point(blockSize *iRow+15, blockSize * iColumn+15);

            p.MouseEnter += (s,e) =>
            {
                var cpSelf = s as ChessPanel;
                if (cpSelf != null)
                {
                    label1.Text = Position[cpSelf.iRow, cpSelf.iColumn];
                }
            };

            groupBox1.Controls.Add(p);
            chessBoardPanels[iRow, iColumn] = p;
        }
    }
}

これらの変数の多くは、後でプログラムの内部で使用していると思いますが、このようなものを見ると頭が痛くなるので、ほとんどの変数を残しました。

デリゲートは非常に強力で便利なユーティリティですが、変数のスコープと混同する可能性があります。これらを使用するときは細心の注意を払い、後で実行する機能単位として扱うようにしてください。したがって、ブロックの作成時ではなく、ブロックの実行時のプログラムの状態にのみ依存できます。お気付きかもしれPositionませんが、デリゲートのスコープ内でローカル変数にアクセスできることを示すためだけに、配列への参照を残しました。これは、技術的にはまだスコープ内にあるためです。構造的には、これを簡単に ChessPanel クラスに移動して、100% ローカルで参照できます。この例は、関数実行の最後にガベージ コレクションされると多くの人が想定している「ローカル」変数がどのようにぶらぶらしてメモリを消費するかを示すことができるため、注意として使用する必要があります。

このコードはテストされておらず、マイナーな構文エラーがある可能性があります。うまくいけば、構造の精神が理解されます。

于 2013-09-12T14:18:31.190 に答える