Пользовательский обработчик событий вызывается дважды? - PullRequest
5 голосов
/ 05 ноября 2011

Я создал обработчик событий, который просто возвращает список объектов, которые я получаю от веб-службы после завершения вызова.

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

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

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

Это класс DataHelper

public class DataHelper
{
    public delegate void DataCalledEventHandler(object sender, List<DataItem> dateItemList);
    public event DataCalledEventHandler DataCalled;

    public DataHelper()
    {

    }

    public void CallData()
    {
        List<DataItem> dataItems = new List<DataItem>();
        //SOME CODE THAT RETURNS DATA
        DataCalled(this, dataItems);
    }
}

Здесь я подписался на мое событие:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
   GetNewDataItems();
}
private void GetNewDataItems()
        {

                try
                {
                    DataHelper dataHelper = new DataHelper();
                    dataHelper.CallData();
                    dataHelper.DataCalled += new DataHelper.DataCalledEventHandler(dataHelper_DataCalled);

                }
                catch
                {
                   //Handle any errors
                }
            }
    }

    void dataHelper_DataCalled(object sender, List<DataItem> dataItemsList)
    {
        //Do something with results
        //NOTE: THIS IS WHERE THE EXCEPTION OCCURS WHEN EVENT IS FIRED FOR SECOND TIME
    }

Ответы [ 2 ]

8 голосов
/ 05 ноября 2011

Возможно, вы добавили делегата дважды, возможно ли это?

В этом случае проблема не в том, кто вызывает делегата, а в том, кто добавляет делегата к событию.

Возможно, высделал что-то вроде ...

private Class1 instance1;

void callback(...)
{
}

void myfunction()
{
    this.instance1.DataCalled += this.callback;
    this.instance1.DataCalled += this.callback;
}

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

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

public void CallData()
{
    List<DataItem> dataItems = new List<DataItem>();
    var handler = this.DataCalled;
    if (handler != null)
        handler(this, dataItems);
}

Редактировать: поскольку теперь я вижу код, очевидно, что каждый раз, когда вы вызываете метод GetNewDataItemsВы подписываетесь каждый раз на событие.Делайте таким образом, что вы подписываетесь только один раз, например, в конструкторе, или сохраняете свою переменную где-нибудь, или отменяете событие по завершении.

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

Вы можете попробовать сделать что-то вроде этого ...

void dataHelper_DataCalled(object sender, List<DataItem> dataItemsList)
{
    // Deregister the event...
    (sender as Class1).DataCalled -= dataHelper_DataCalled; 

    //Do something with results
}

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

Вместо события, возможно, вам нужен только делегат.Конечно, вы должны установить для поля делегата значение NULL, если вы хотите освободить делегата.

// in data helper class

private DataHelper.DataCalledEventHandler myFunctor;

public void CallData(DataHelper.DataCalledEventHandler functor)
{
    this.myFunctor = functor;
    //SOME CODE THAT RETURNS DATA
}

// when the call completes, asynchronously...
private void WhenTheCallCompletes()
{
    var functor = this.myFunctor;
    if (functor != null)
    {
        this.myFunctor = null;
        List<DataItem> dataItems = new List<DataItem>();
        functor(this, dataItems);
    }
}
    
// in your function
...    dataHelper.CallData(this.dataHelper_DataCalled);    ...
2 голосов
/ 05 ноября 2011

Следующие строки в вашем коде должны быть перевернуты. Это

Эти строки

dataHelper.CallData();
dataHelper.DataCalled += new DataHelper.DataCalledEventHandler(dataHelper_DataCalled);

Должно быть:

dataHelper.DataCalled += new DataHelper.DataCalledEventHandler(dataHelper_DataCalled);
dataHelper.CallData();

Поскольку сначала необходимо подключить обработчик события, а затем вызвать другие методы объекта, которые могут вызвать событие

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...