2015-07-05 3 views
2

Есть ли что-нибудь неправильно с подпиской на событие сПодписавшись на события с = а + =

MyPopup.CustomPopupPlacementCallback = popupFixCentered; 

вместо:

MyPopup.CustomPopupPlacementCallback += popupFixCentered; 

Например, если я меняю различный обратный вызов от другого метод Я хочу убедиться, что у меня есть только один обратный звонок, подписанный без необходимости - = правильный.

+0

Если вы попробуете это, делает он компилируется? – sstan

+0

@sstan да, он компилируется, и у меня нет проблем с этим. MyPopup - всплывающее окно, созданное в xaml. Нажав одну кнопку, я выравниваю всплывающее окно слева, а с другой кнопки я делаю его по центру. –

ответ

4

Ну, похоже, вы не пробовали. Если вы сделали, вы получите следующее сообщение об ошибке компиляции:

The event 'XXX' can only appear on the left hand side of += or -= (except when used from within the type 'YourClass')

Ошибка довольно ясна: вы можете использовать только += и -= операторов на мероприятии.

Если вы пытаетесь присвоить event из в класс, который определяет событие, то он будет «работать». Но причина, по которой он может быть назначен на event в этом случае, состоит в том, что он фактически не имеет доступа к событию. Это доступ к автогенерированному частному экземпляру делегата, который вы, возможно, не осознаете, на самом деле там.

Цитируя Chris Burrows' article по теме:

outside of the class or struct that defines a field-like event E, binding to the name E resolves to the event itself, on which the only legal operation is calling an accessor; inside the class or struct that defines a field-like event E, binding to the name E resolves to the private delegate field.

Чтобы понять это, вам нужно визуализировать, что при определении события, такие как:

public event EventHandler MyEvent; 

... что вы не делаете см., что он фактически переводится во что-то вроде этого (я копирую это с Jon Skeet's article on events and delegates. Также обратите внимание, что точный код, который он переводит, изменился между версиями C#, поэтому он может быть немного иным, но общий Идея - это s AME):

private EventHandler _myEvent; 

public event EventHandler MyEvent 
{ 
    add 
    { 
     lock (this) 
     { 
      _myEvent += value; 
     } 
    } 
    remove 
    { 
     lock (this) 
     { 
      _myEvent -= value; 
     } 
    }   
} 

Итак, когда вы получаете доступ MyEvent из вне класса, вы можете только ссылаться на add и remove метод через в += и -= операторов.

Но из в класс, доступ к MyEvent означает что-то другое. Он фактически становится ссылкой на эту приватную переменную делегата _myEvent, которую вы не видите, но она есть. Поскольку это тип делегата, вы можете использовать оператор присваивания (=).


Таким образом, чтобы достичь того, чего вы хотите, вы можете определить публичный метод в том же классе, что определяет событие, и использовать этот метод, чтобы установить новый обработчик событий.

Что-то вроде этого:

public class MyClass 
{ 
    public event EventHandler MyEvent; 

    public void setSingleEventHandler(EventHandler eventHandler) 
    { 
     this.MyEvent = eventHandler; 
    } 
} 

Но если вы собираетесь сделать это, то он побеждает цель event типа. Если вы хотите, чтобы вызвать один обработчик событий самого больший в любой момент времени, то определение его таким образом (без использования event ключевого слова) имеет смысл:

public class MyClass 
{ 
    public EventHandler MyEvent { get; set; } 
} 

Ссылку

Джон тарелочки статья : Delegates and Events

Крис Берроуз статье: (также проверить остальные серии): Events get a little overhaul in C# 4, Part II: Semantic Changes and +=/-=

0

Я просто проверял. Да, вы можете использовать оператор = для назначения событию. (Edit: Видимо только из того же класса)

delegate void Foo(); 
event Foo bar; 
Method() 
{ 
    bar =() => { Console.WriteLine("1"); }; 
    bar(); 
    bar =() => { Console.WriteLine("2"); }; 
    bar(); 
} 

Производит вывод:

1 
2 

Но если вы попытаетесь присвоить вне класса, это даст вам ошибку.

Вы можете обойти это, используя набор метод Java-стиль:

SetBar(Foo foo) 
{ 
    bar = foo; 
} 

только раз, когда я когда-либо рекомендовать Java конвенции для внешнего доступа свойств :)

+1

Вы можете сделать это только для автоматически реализованных событий и только изнутри класса. – PetSerAl

+0

Спасибо, я не проверил его достаточно тщательно. – RogueCSDev

Смежные вопросы