Как получить события для обработки в определенном порядке в C #? - PullRequest
0 голосов
/ 25 июля 2009

У меня была идея зарегистрировать событие на базовой пользовательской странице для каждой кнопки. Я могу проверить, было ли это сохранение или редактирование, а затем выполнить авторизацию и проверку. Производные страницы будут по-прежнему обрабатывать событие click, чтобы выполнить спецификацию для сохранения на этой странице. Я не был уверен, какие события произойдут первыми. (но, вероятно, это в порядке соединения). Если родительская страница запускается первой, я могу получить ожидаемое поведение, установив свойство IsAuthorized или IsValidated и проверив его в обработчике кликов каждой производной страницы.

Как бы то ни было, есть ли способ убедиться, что обработчик событий базовой страницы запускается и завершается первым, или есть какой-нибудь способ спасти это?

РЕДАКТИРОВАТЬ: я упускаю из виду более простой дизайн, который не требует добавления кода котельной пластины для каждой кнопки редактирования / сохранения / обновления кнопки в приложении? И как правильно общаться с другим человеком? Например, базовая страница должна сообщать об успешном или неудачном подтверждении, производный класс должен сообщать об успешном или неудачном сохранении, чтобы ее можно было записать в ходе аудита.

//Base page-- seems like this will work if events happen in order of wireup.
protected override void OnInit(EventArgs e)
{
    foreach (Control possibleButton in Controls)
    {
        if(possibleButton is Button)
        {
            Button button = (Button) possibleButton;
            button.Command += ButtonCommandPreconditions;
        }
    }
    base.OnInit(e);
    foreach (Control possibleButton in Controls)
    {
        if(possibleButton is Button)
        {
            Button button = (Button) possibleButton;
            button.Command += ButtonCommandPostconditions;
        }
    }
}

void ButtonCommandPreconditions(object sender, CommandEventArgs e)
{
        if(e.CommandName=="Save" || e.CommandName=="Edit")
        {
            //Stuff that needs to happen before other handler   
            //Validate, display failures-- maybe set IsValdated property
            //Check for POST/GET, throw exception on GET.
            //Check for ID, throw exception on anonymous user
            //Check for authorization
            //Display authorization failures-- maybe set IsAuthorized property 
        }
}

void ButtonCommandPostconditions(object sender, CommandEventArgs e)
{
        if(e.CommandName=="Save" || e.CommandName=="Edit")
        {
             //Stuff that needs to happen *after* other handler
            //Log save
        }
}

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

Ответы [ 3 ]

5 голосов
/ 25 июля 2009

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

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

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

РЕДАКТИРОВАТЬ для новых вопросов:

И как правильно одному организатору мероприятия общаться с другим?

Вы должны увидетьмой ответ в этого поста. Обработчики событий на самом деле не предназначены для связи друг с другом в ASP.Net (по крайней мере, для обработчиков событий жизненного цикла WebControl / page), так как нет гарантии на порядок запуска. Если у вас есть обработчики событий, полагающиеся на информацию, устанавливаемую в одноуровневых обработчиках событий, возможно, в вашем дизайне есть недостаток.

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

На самом деле есть несколько способов справиться с этим. Во-первых, просто сделайте вызов базового класса абстрактным или виртуальным методом, который можно переопределить на производных страницах. Во время обработки нажатия кнопки на вашей базовой странице выполните всю проверку, затем вызовите абстрактный метод «DoSave ()» ваших производных страниц и убедитесь, что он успешно выполнен.

Или напишите свой собственныйсобытия, и поднять их, когда это будет необходимо. Создайте событие «Проверка» в своем базовом классе и попросите ваши производные страницы подписаться на него, если им нужно будет ответить. Убедитесь, что ваш базовый класс повышает его, когда он завершит проверку. Создайте «сохраненное» событие в вашем базовом классе, обработчик события для него и попросите подписаться на него ваш базовый класс. Пусть ваши производные классы вызовут событие , когда они закончат сохранение. Теперь базовый класс может обрабатывать его регистрацию.

Я хотел бы добавить, что кажется, что вы загружаете очень много вещей в щелчки кнопок базового класса. Можете ли вы выполнить анонимный ID и проверку GET / POST при отображении страницы, и просто не отображать кнопки, если у них нет разрешения?

3 голосов
/ 31 июля 2009

Хотя я не готов предложить решение (поскольку это потребовало бы довольно сложного понимания вашего дизайна), не говоря уже о том, чтобы разделить вашу логику «Сохранить» (и подобные события) в их собственную иерархию классов и вызватьих в одной жизни от обработчиков событий. Тем не менее, я могу прокомментировать ваш оригинальный вопрос (перед вашим редактированием выделен жирным шрифтом). Проблема с вашей настройкой заключается в том, что, хотя вы можете генерировать события в определенном порядке, ни одно событие в .Net Framework не гарантирует порядок доставки. Они могут выглядеть упорядоченными при тестировании на вашем компьютере разработчика, но при практическом развертывании, когда нагрузка на систему возрастет, события будут в первую очередь отложены в пользу других операций. Событие прибытие их слушателям может по существу стать случайным.

Вы никогда не должны строить свою логику на основе порядка, в котором получены события. Каждое событие должно учитывать только текущее состояние, оно не может предполагать ничего о каком-либо другом событии. Ваша цепочка событий прервется, когда вам это понадобится больше всего.

1 голос
/ 25 июля 2009

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

Вы можете избавить себя от некоторых головных болей, обрабатывая события Button Command в вашем базовом классе, а затем делегируя их своим производным классам с новым реализованным в нем событием ButtonCommand. Единственным реальным изменением существующего производного кода будет более пристальное внимание к параметру «отправитель» к производному обработчику событий. Например:

class BaseClass
{
    public event CommandEventHandler ButtonCommand = delegate { };

    protected override void OnInit(EventArgs e)
    {
        foreach (Control possibleButton in Controls)
        {
            if (possibleButton is Button)
            {
                Button button = (Button) possibleButton;
                button.Command += AnyButtonCommandHandler;
            }
        }
        base.OnInit(e);
    }

    void AnyButtonCommandHandler(object sender, CommandEventArgs e)
    {
        // validation logic. if fails, return.

        ButtonCommand(sender, e);
    }
}

class DerivedClass : BaseClass
{
    public DerivedClass()
    {
        base.ButtonCommand += base_ButtonCommand;
    }

    void base_ButtonCommand(object sender, CommandEventArgs e)
    {
        if (sender == button1) { ... }
        else if (sender == button2) { ... }
        // etc.
    }
}

Вы также можете подумать о замене события ButtonCommand на protected void OnButtonCommand(object sender, CommandEventArgs e) (или сделать оба);тогда вы можете просто переопределить OnButtonCommand в своем производном классе.

...