기존 이벤트 핸들러의 이름을 어떻게 변경합니까?

세자르 아모 림

Windows Forms에서 메서드 이름 (예 button1_Click:)을 다른 이름으로 변경하면 더 이상 작동하지 않습니다.

내가 기억하는 한 콘솔 응용 프로그램에서 원하는대로 메서드의 이름을 지정할 수 있기 때문에 이것이 이상합니다. 나는 무슨 일이 일어나고 있는지 이해하려고 노력하고 있습니다.

이러한 메서드의 이름 (예 :)을 어떻게 변경할 수button1_Click 있습니까?

Theraot

이 질문은 메서드 이름을 바꾸면 양식 디자이너의 작동이 중지되는 경우에 대한 것입니다. 이벤트가 일반적으로 어떻게 작동하는지 (내가 생각할 수있는 모든 것) 다루었지만.


어떻게 된 거예요?

경험하는 것은 양식 디자이너의 아티팩트입니다.

물론 원하는 메서드 이름을 가질 수 있습니다. 문제는 양식 디자이너가 더 이상 작동하지 않는 이벤트에 메서드 이름을 연결 한 후 메서드 이름을 변경하면 양식 디자이너가 이러한 메서드를 백그라운드 이벤트에 바인딩한다는 것입니다. 방법을 찾을 수 없습니다).


이벤트 핸들러에 적절한 이름 제공

Visual Studio에서 이벤트를 바인딩하려는 개체의 속성을 확인한 다음 패널 상단에서 이벤트를 선택합니다.

속성 패널의 이벤트 탭을 엽니 다.

사용 가능한 이벤트 목록이 표시되며 기존 메서드를 바인딩하거나 새 메서드의 이름을 입력 할 수 있습니다.

바인딩 할 새 방법 만들기 선택


이미 나사를 조인 ​​경우 어떻게 고쳐야합니까?

이로 인해 디자이너가 나타나지 않으면 디자이너가 생성 한 코드 파일을 편집해야합니다. 디자이너가 생성 한 파일에는 양식의 이름과 그 뒤에 오는 .Designer.cs(예 Form1.Designer.cs:)이 있으며 솔루션 탐색기에서 찾을 수 있습니다.

디자이너가 생성 한 코드 파일 찾기

참고 : 파일을 표시하려면 양식에 생성 된 하위 트리를 확장해야 할 수 있습니다.

여기에 다음과 같은 줄이 있습니다.

this.button1.Click += new System.EventHandler(this.button1_Click);

그리고 Visual Studio는 button1_Click정의되지 않았 음을 알려줍니다 . 여기에서 메서드 이름을 새 이름으로 편집하거나 줄을 제거하여 디자이너가 다시 작업하도록하고 새 메서드를 바인딩 할 수 있습니다.


번거 로움없이 기존 메서드 이름 바꾸기

이름 바꾸기 대화 상자를 불러올 수 있습니다. 이것은 여러 가지 방법으로 수행 할 수 있습니다.

  • 메뉴에서 : Edit-> Refactor->Rename
  • 방법 이름의 상황에 맞는 메뉴 : Refactor->Rename
  • 메서드 이름에 커서를 놓고 입력 Alt + Shift + F10한 다음Rename
  • 메서드 이름에 커서를 놓고 F2

참고 : Visual Studio를 사용자 지정할 수 있으며 위의 메뉴 및 바로 가기 키는 변경 될 수 있습니다.

이름 바꾸기 대화 상자는 다음과 같습니다.

이름 바꾸기 대화 상자 사용

여기에 메서드의 새 이름을 입력 할 수 있으며 이렇게하면로드 된 프로젝트와 함께 해당 메서드에 대한 참조 또는 호출도 변경됩니다. 여기에는 Forms Designer에서 생성 한 코드가 포함됩니다.


이벤트 핸들러를 손으로 바인딩

양식 디자이너가 수행하는 모든 작업은 양식을 쉽게 편집하고 사용자를 대신하여 코드를 작성할 수있는 UI를 제공하는 것입니다. 스스로 코드를 작성할 수 없다고 생각하도록 속이지 마십시오.

In fact, you can create your own methods and even bind them to the events of your Form. I have been saying "bind" because it is easier to understand at this level, although the accepted lingo is subscribe. So what we are going to do, is create a button and subscribe to its Click event.

First let's take a look at the class of your form, it looks something like this:

using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

Notice it says partial, that means that there could be more code for this class in another file, in fact that is the file Form1.Designer.cs where the forms designer has been adding code.

Second notice it calls a method InitializeComponent inside the constructor of the form. This method has been created by the forms designer and it takes responsibility of initializing all the controls and components you have added using the forms designer (hence the name of the method).

Now, let's say we want to add a button without the forms designer we can do it like this:

using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private Button myButton;

        public Form1()
        {
            InitializeComponent();

            // Create a new Button
            myButton = new Button();

            // Set the properties of the Button
            myButton.Location = new System.Drawing.Point(50, 12);
            myButton.Size = new System.Drawing.Size(100, 23);
            myButton.Text = "My Button";

            // Add the Button to the form
            this.Controls.Add(myButton);
        }
    }
}

We have created a private field named myButton of type Button that will hold the new button. Then inside the constructor we add some new lines to create a new Button and assign it to myButton and give it position (Location), Size and Text. And finally we have added the newly created button to the Controls of the form.

Now we want to add an event handler for the Click event on this new button. Remember that this button is not in the forms designer, we we are going to have to do it "by hand".

In order to do so, add the new method (you can named whatever you want):

        private void WhenClick(object sender, System.EventArgs e)
        {
            /* Code */
        }

And then add it as an event handler for the Click event of the button (inside the constructor):

            // Add an event handler
            myButton.Click += new System.EventHandler(WhenClick);

Notice we are not calling WhenClick. instead we are making a reference to it.

Then we are creating a new Delegate of type System.EventHandler that will wrap the reference to the method WhenClick. I suggest to learn about Using Delegates.

I repeat: we are not calling WhenClick. If we were to call WhenClick we would do something like this: WhenClick(param1, param2). Please note that this is not what we are doing here, we haven't added parenthesis (/*...*/) after the method name, so we are not doing a method call.


You can also use some syntactic sugar to make all this easier:

        public Form1()
        {
            InitializeComponent();

            // Create a new Button and set its properties
            myButton = new Button()
            {
                Location = new System.Drawing.Point(50, 12),
                Size = new System.Drawing.Size(100, 23),
                Text = "My Button"
            };


            // Add the Button to the form
            this.Controls.Add(myButton);

            // Add an event handler (the compiler infers the delegate type)
            myButton.Click += WhenClick;
        }

You can even make the event handler an anonymous method:

            // Add an event handler (the compiler infers the delegate type)
            myButton.Click += (sender, e) =>
            {
                /* code */
            };

What you see here is a C# Lambda expression (more info at MSDN Lambda expressions). Get used to these syntax, because you will see them more and more often.


Understanding events

You have already seen code like this:

button1.Click += button1_Click;

As I told you we are passing a delegate object that has a reference to button1_Click. But that's not all that happens here... we are also giving it to Click.

Let's recapitulate and see how delegates behave. You can think about a delegate like an object that holds a method, or a pointer to a function if you prefer.

To understand this, I'll present some examples you can run as console applications. The first one shows that you can change the method that a delegate points to during runtime:

// Console Application Example #1 ;)
static void Main()
{
    Func<int, int> myfunc = null;

    myfunc = Add2;
    Console.WriteLine(myfunc(7)); // This prints 9
    myfunc = MultBy2;
    Console.WriteLine(myfunc(7)); // This prints 14
}

static int Add2(int x)
{
    // This method adds 2 to its input
    return x + 2;
}

static int MultBy2(int x)
{
    // This method  multiplies its input by 2
    return x * 2;
}

Notice myfunc is typed as Func<int, int> this is a generic delegate type that takes an int and returns an int.

Also notice that when I say myfunc = Add2;, it is not calling Add2 (there are no parenthesis there), it is passing a reference of the method itself. the same is true for myfunc = MultBy2;: it is not calling MultBy2, we are passing it.

Using anonymous methods via lambda expressions you can write equivalent code is less lines:

// Console Application Example #1 ;)
static void Main()
{
    Func<int, int> myfunc = null;

    // This anonymous method adds 2 to its input
    myfunc = x => x + 2;
    Console.WriteLine(myfunc(7)); // This prints 9

    // This anonymous method  multiplies its input by 2
    myfunc = x => x * 2;
    Console.WriteLine(myfunc(7)); // This prints 14
}

Notice that we have two anonymous methods here: x => x + 2 and x => x * 2. The first one (x => x + 2) is equivalent to the method Add2 we had before, and the second one (x => x * 2) is equivalent to the method MultBy2 we had before.

In this example I want you to see that the same delegate can point to different methods along the time. This is accomplished by having a variable that points to the methods!


For the second example, I'll present the "callback" pattern. That is a common pattern in which you pass a delegate as a "callback", that is: something that will be called "back to you" from the code you are calling:

// Console Application Example #2 ;)
static void Main()
{
    Func<int, bool> filter = IsPair;
    // An array with numbers
    var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
    PrintFiltered(array, filter);
}

static bool IsPair(int x)
{
    // True for pair numbers
    return x % 2 == 0;
}

static void PrintFiltered(int[] array, Func<int, bool> filter)
{
    if (array == null) throw new ArgumentNullException("array");
    if (filter== null) throw new ArgumentNullException("filter");
    foreach (var item in array)
    {
        if (filter(item))
        {
            Console.WriteLine(item);
        }
    }
}

Outputs:

2
4
8

In this code we are having a variable filter that points to the method IsPair. I'll repeat this again and and again: in the line Func<int, bool> filter = IsPair; we are not calling the method IsPair, instead we are taking a reference to it.

Of course, it is possible to do the same without declaring the filter variable, you can pass the method reference directly:

// Console Application Example #2 ;)
static void Main()
{
    // An array with numbers
    var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
    PrintFiltered(array, IsPair); //<---
}

static bool IsPair(int x)
{
    // True for pair numbers
    return x % 2 == 0;
}

static void PrintFiltered(int[] array, Func<int, bool> filter)
{
    if (array == null) throw new ArgumentNullException("array");
    if (filter== null) throw new ArgumentNullException("filter");
    foreach (var item in array)
    {
        if (filter(item))
        {
            Console.WriteLine(item);
        }
    }
}

I cannot stress this hard enough: When I say PrintFiltered(array, IsPair); it is not calling IsPair, it is passing it as a parameter to PrintFiltered. Here effectively you have a method (PrintFiltered) that can take a reference to another method (IsPair) as a reference.

Of course you can write the same code using an anonymous method that replaces IsPair:

// Console Application Example #2 ;)
static void Main()
{
    // An array with numbers
    var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
    PrintFiltered(array, x => x % 2 == 0);
}

static void PrintFiltered(int[] array, Func<int, bool> filter)
{
    if (array == null) throw new ArgumentNullException("array");
    if (filter== null) throw new ArgumentNullException("filter");
    foreach (var item in array)
    {
        if (filter(item))
        {
            Console.WriteLine(item);
        }
    }
}

Outputs:

2
4
8

In this example x => x % 2 == 0 is an anonymous method that is equivalent to the method IsPair we had before.

We have successfully filtered the array to only show the numbers that are pair. You can easily reuse the same code for a different filter. For example, the following line can be used to output only the items in the array that are less than 10:

    PrintFiltered(array, x => x < 10);

Outputs:

1
2
3
4
7
8
9

With this example I want to show you that you can take advantage of the delegates to improve the reusability of your code, by having parts that change depending on the delegate you pass.


Now that - hopefully - we understand this, it is not hard to think that you could have a list of Delegate objects, and call them in succession:

// Console Application Example #3 ;)
static void Main()
{
    // List<Action<int>> is a List that stores objects of Type Action<int>
    // Action<int> is a Delegate that represents methods that
    //  takes an int but does not return (example: void func(int val){/*code*/})
    var myDelegates = new List<Action<int>>();

    // We add delegates to the list
    myDelegates.Add(x => Console.WriteLine(x));
    myDelegates.Add(x => Console.WriteLine(x + 5));

    // And we call them in succesion
    foreach (var item in myDelegates)
    {
        item(74);
    }
}

Outputs:

74
79

You can see both anonymous methods (x => Console.WriteLine(x) and Console.WriteLine(x + 5)) has been called, one after the other... this happens inside the foreach loop.

Now, we can accomplish similar results with a multicast delegate:

// Console Application Example #3 ;)
static void Main()
{
    // This is a delegate... we haven't give it a method to point to:
    Action<int> myDelegates = null;

    // We add methods to it
    myDelegates += x => Console.WriteLine(x);
    myDelegates += x => Console.WriteLine(x + 5);

    // And we call them in succession
    if (myDelegates != null) // Will be null if we don't add methods
    {
        myDelegates(74);
    }
}

Outputs:

74
79

Again, both anonymous methods has been called. And this is exactly how events work. The default implementation of an event uses a multicast delegated wrapped inside. Custom implementation of an event may use a list or similar structure to hold the delegates.

Now, if the event is just a list of delegates... that means the event is keeping a reference to all the methods it wants to call. And it also means that you could remove delegates from the list (or add more than one).

If you want to unsubscribe or unbind from an event, you can do so like this:

this.button1.Click -= button1_Click;

For a delegate object to an anonymous method it is a little bit more complicated, because you will need to keep the delegate in a variable to able to pass it back for removal:

Action<int> myDelegates = null;

// Create the delegate
var myDelegate = x => Console.WriteLine(x);

// Add the delegate
myDelegates += myDelegate;

// ...

// Remove the delegate
myDelegates -= myDelegate;

Did you say custom implementation of an event?

Does that means you can create your own events? Yes, and yes. If you want to publish an event in one of your classes you can declare it just like any other member.

This is an example that uses a multicast delegate:

// Event declaration:
public event EventHandler MyEvent;

// Method to raise the event (aka event dispatcher):
priavet void Raise_MyEvent()
{
    var myEvent = MyEvent;
    if (myEvent != null)
    {
        var e = new EventArgs();
        myEvent(this, e);
    }
}

For a custom implementation take this example:

// List to hold the event handlers:
List<EventHandler> myEventHandlers = new List<EventHandler>();

// Event declaration:
event EventHandler MyEvent
{
    add
    {
        lock (myEventHandlers)
        {
            myEventHandlers.Add(value);
        }
    }
    remove
    {
        lock (myEventHandlers)
        {
            myEventHandlers.Remove(value);
        }
    }
}

// Method to raise the event (aka event dispatcher):
private void Raise_MyEvent()
{
    var e = new EventArgs();
    foreach (var item in myEventHandlers)
    {
        item(this, e);
    }
}

Hopefully this not hard to read, now that you know how events work. The only details should be lock, it is there because List is not thread-safe. You could also use a thread-safe data structure or a different locking mechanism, I kept this one for simplicity.

Even if you don't write your own events, there are a few things to learn from here:

  1. Event handlers execute consecutively (by default), so it is good idea that event handlers execute fast (maybe defer to asynchronous operations for the hard work) to prevent "clogging" the event dispatcher.
  2. The event dispatcher usually don't handle exceptions (it can be done), so it is good idea to avoid throwing excepting in event handlers.
  3. The "publisher" of the event is keeping a list of the event handlers, it is a good idea to unsubscribe when you don't need need the event handler anymore.

Notes:

While looking for example I found the series of articles "Delegates in C# - Attempt to Look Inside" by Ed Guzman (Part 1, Part 2, Part 3 and Part 4) very easy to read - although a bit outdated - you should check them out. You may want to read the Evolution of Anonymous Functions in C# for a grasp of what's missing.

Some commonly used Delegate Types built-in in .NET include:

  • Generic
    • Action<*> (that is: Action<T>, Action<T1, T2> ...)
    • Func<*, TResult> (that is: Func<T, TResult>, Func<T1, T2, TResult> ...)
    • EventHandler<TEventArgs>
    • Comparison<T>
    • Converter<TInput, TOutput>
  • Non Generic
    • Action
    • Predicate
    • EventHandler
    • ThreadStart
    • ParametrizedThreadStart

You may be interested in LINQ.

Threading and thread-safety it a even broader topic than delegates and events, don't rush to understand it all.

일반적으로 Lambda Expression 및 C #과 함께 플레이하려면 LINQPad 복사본을 구하는 것이 좋습니다 . 이를 통해 테스트를위한 새 프로젝트를 만드는 번거 로움을 줄일 수 있습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

두 개의 비동기 연결된 이벤트 핸들러를 어떻게 수신합니까?

분류에서Dev

Eventbrite : 기존 반복 이벤트의 시작 날짜를 변경하려면 어떻게합니까

분류에서Dev

Android를 처음 사용하는 경우 프래그먼트 내부의 요소에 대한 이벤트 핸들러를 어떻게 초기화합니까?

분류에서Dev

새 폴더의 기본 이름을 어떻게 변경합니까?

분류에서Dev

JavaScript의 이벤트 핸들러는 이벤트 루프에서 어떻게 처리됩니까?

분류에서Dev

VB 델리게이트를 파이썬 이벤트 핸들러로 어떻게 변환합니까?

분류에서Dev

이벤트 핸들러에 인수를 어떻게 전달합니까?

분류에서Dev

Vue PWA 앱의 앱 이름을 어떻게 변경합니까?

분류에서Dev

Kentico 10-기존 사용자의 사용자 이름을 어떻게 업데이트합니까?

분류에서Dev

canvas.bind (event, handler)는 이벤트 핸들러에 이벤트를 어떻게 전달합니까?

분류에서Dev

Python / Pandas-열 머리글 내의 기존 데이터를 잃지 않고 DataFrame의 열 머리글 이름을 어떻게 변경합니까?

분류에서Dev

다른 핸들러에서 angularjs 이벤트 핸들러를 어떻게 트리거 할 수 있습니까?

분류에서Dev

요소 제거 후 jquery 이벤트 핸들러는 어떻게됩니까?

분류에서Dev

Service Stack Raw보기 폴더의 이름은 어떻게 변경합니까?

분류에서Dev

핸들러 내부에서 이벤트 핸들러가 첨부 된 요소를 어떻게 얻습니까?

분류에서Dev

%가 구분 기호 인 Windows 파일의 이름을 일괄 변경하려면 어떻게해야합니까?

분류에서Dev

이 이벤트 핸들러를 jQuery 플러그인에 어떻게 바인딩합니까?

분류에서Dev

React는 이벤트 핸들러에 전달 된 함수 / 콜백을 어떻게 처리합니까?

분류에서Dev

React에서 테이블의 이벤트 핸들러에서 조건부 렌더링을 확인하려면 어떻게해야합니까?

분류에서Dev

tkinter : 동일한 핸들러 내에서 위젯 변경 사이에 지연을 어떻게 삽입합니까?

분류에서Dev

이 이벤트 핸들러에서 반복적 인 코드를 피하려면 어떻게해야합니까?

분류에서Dev

JavaScript의 이벤트 핸들러에 올바른이 컨텍스트를 어떻게 제공하거나 바인딩합니까?

분류에서Dev

파일 확장자의 기본 아이콘을 어떻게 변경합니까?

분류에서Dev

기존 Twilio 번호의 속성을 변경하려면 어떻게합니까?

분류에서Dev

JavaFX 2.2 : 기존 탭의 제목을 어떻게 변경합니까?

분류에서Dev

onChange 핸들러는 어떻게 이전 상태의 변수에 액세스합니까?

분류에서Dev

이벤트 핸들러 외부에서 변수를 어떻게 사용할 수 있습니까?

분류에서Dev

AppCenter SDK for C #에서 TrackError에 대한 이벤트 핸들러를 어떻게 등록합니까?

분류에서Dev

RactiveJS로 jQuery 이벤트 핸들러를 언제 (또는 어떻게) 설정합니까?

Related 관련 기사

  1. 1

    두 개의 비동기 연결된 이벤트 핸들러를 어떻게 수신합니까?

  2. 2

    Eventbrite : 기존 반복 이벤트의 시작 날짜를 변경하려면 어떻게합니까

  3. 3

    Android를 처음 사용하는 경우 프래그먼트 내부의 요소에 대한 이벤트 핸들러를 어떻게 초기화합니까?

  4. 4

    새 폴더의 기본 이름을 어떻게 변경합니까?

  5. 5

    JavaScript의 이벤트 핸들러는 이벤트 루프에서 어떻게 처리됩니까?

  6. 6

    VB 델리게이트를 파이썬 이벤트 핸들러로 어떻게 변환합니까?

  7. 7

    이벤트 핸들러에 인수를 어떻게 전달합니까?

  8. 8

    Vue PWA 앱의 앱 이름을 어떻게 변경합니까?

  9. 9

    Kentico 10-기존 사용자의 사용자 이름을 어떻게 업데이트합니까?

  10. 10

    canvas.bind (event, handler)는 이벤트 핸들러에 이벤트를 어떻게 전달합니까?

  11. 11

    Python / Pandas-열 머리글 내의 기존 데이터를 잃지 않고 DataFrame의 열 머리글 이름을 어떻게 변경합니까?

  12. 12

    다른 핸들러에서 angularjs 이벤트 핸들러를 어떻게 트리거 할 수 있습니까?

  13. 13

    요소 제거 후 jquery 이벤트 핸들러는 어떻게됩니까?

  14. 14

    Service Stack Raw보기 폴더의 이름은 어떻게 변경합니까?

  15. 15

    핸들러 내부에서 이벤트 핸들러가 첨부 된 요소를 어떻게 얻습니까?

  16. 16

    %가 구분 기호 인 Windows 파일의 이름을 일괄 변경하려면 어떻게해야합니까?

  17. 17

    이 이벤트 핸들러를 jQuery 플러그인에 어떻게 바인딩합니까?

  18. 18

    React는 이벤트 핸들러에 전달 된 함수 / 콜백을 어떻게 처리합니까?

  19. 19

    React에서 테이블의 이벤트 핸들러에서 조건부 렌더링을 확인하려면 어떻게해야합니까?

  20. 20

    tkinter : 동일한 핸들러 내에서 위젯 변경 사이에 지연을 어떻게 삽입합니까?

  21. 21

    이 이벤트 핸들러에서 반복적 인 코드를 피하려면 어떻게해야합니까?

  22. 22

    JavaScript의 이벤트 핸들러에 올바른이 컨텍스트를 어떻게 제공하거나 바인딩합니까?

  23. 23

    파일 확장자의 기본 아이콘을 어떻게 변경합니까?

  24. 24

    기존 Twilio 번호의 속성을 변경하려면 어떻게합니까?

  25. 25

    JavaFX 2.2 : 기존 탭의 제목을 어떻게 변경합니까?

  26. 26

    onChange 핸들러는 어떻게 이전 상태의 변수에 액세스합니까?

  27. 27

    이벤트 핸들러 외부에서 변수를 어떻게 사용할 수 있습니까?

  28. 28

    AppCenter SDK for C #에서 TrackError에 대한 이벤트 핸들러를 어떻게 등록합니까?

  29. 29

    RactiveJS로 jQuery 이벤트 핸들러를 언제 (또는 어떻게) 설정합니까?

뜨겁다태그

보관