Принудительный метод для запуска во время события - PullRequest
3 голосов
/ 05 августа 2011

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

У меня также есть мастер-страница, которая встраивает другую мастер-страницу.Первая мастер-страница устанавливает базовый заголовок (Google), следующая мастер-страница добавляет заголовок (Calendar), а страница также добавляет заголовок (21 мая 2011 г.).

Результат должен быть:

21 May 2011 :: Calendar :: Google

И это тот случай, когда PrependTitle запускается во время события Page_Init.Однако, когда метод запускается во время Page_Load, получаются следующие результаты:

Google

Итак, это подводит меня к вопросу: Как можно обеспечить, чтобыметод будет доступен только во время определенных событий жизненного цикла?

// The Method Mentioned
public static class PageExtensions
{
    public static void PrependTitle(this Page page, string newTitle)
    {
        page.Title = newTitle + " " + Global.TITLE_DELIMITER + " " + page.Title;
    }
}

Ответы [ 4 ]

2 голосов
/ 13 августа 2011

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

class AppsBasePage : Page
{
   abstract void PrependTitle(string title);
}
class PageWithTitlePrepended : AppsBasePage
{
   private void PrependTitle(string title)
   {
        Title = String.Format("{0} {1} {2}", newTitle, Global.TITLE_DELIMITER, Title); 
   }
   protected sealed override void Page_Init(object sender, EventArgs e)       
   {
        PrependTitle("This is a title")
   }
}
class ActualPageInApp: PageWithTitlePrepended
{
   override void Page_Load(object s, EventArgs e) 
   {
      // can't access PrependTitle here
   } 
}

Это решает ваш вопрос жирным шрифтом, но я не уверен, что именно эта ситуация вызываетпроблема с PrependTitle конкретно.Я думаю, что больше кода / контекста потребуется для решения вашей актуальной проблемы

1 голос
/ 16 августа 2011

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

public static bool CalledFromInit()
{
    //Grab the current Stack Trace and loop through each frame
    foreach(var callFrame in new StackTrace().GetFrames())
    {
        //Get the method in which the frame is executing
        var method = callFrame.GetMethod();

        //Check if the method is Control.OnInit (or any other method you want to test for)
        if(method.DeclaringType == typeof(Control) && method.Name == "OnInit")
            //If so, return right away
            return true;
    }

    //Otherwise, we didn't find the method in the callstack
    return false;
}

Тогда вы бы использовали это как:

public static void PrependTitle(this Page page, string newTitle)
{
    //If we aren't called from Init, do something
    if (!CalledFromInit())
    {
        //We could either return to silently ignore the problem
        return;

        //Or we could throw an exception to let the developer know they 
        //   did something wrong
        throw new ApplicationException("Invalid call to PrependTitle");
    }

    //Do the normally processing
    page.Title = newTitle + " " + Global.TITLE_DELIMITER + " " + page.Title;
}

Однако я бы предостерег, что трассировка стека не самая надежная вещь. В выпуске код можно оптимизировать так, чтобы метод Control.OnInit был встроен, чтобы ваш код не смог увидеть его в стеке вызовов. Вы можете заключить эту проверку в блок #if DEBUG, чтобы она выполнялась только во время разработки. В зависимости от вашего варианта использования может оказаться достаточно уловить эту проблему, находясь в режиме отладки, и не пытаться выполнить проверку в RELEASE. Но это зависит от вас.

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

public abstract class BasePage : Page
{
    private bool _executingInit;
    protected internal override void OnPreInit(EventArgs e)
    {
        _executingInit = true;
        base.OnPreInit(e);
    }

    protected internal override void OnInitComplete(EventArgs e)
    {
        base.OnInitComplete(e);
        _executingInit = true;
    }

    public void PrependTitle(string newTitle)
    {
        if (!_executingInit)
            throw new ApplicationException("Invalid call to PrependTitle.");

        Title = newTitle + " " + Global.TITLE_DELIMITER + " " + Title;
    }
}

Таким образом, PrependTitle будет генерировать исключение, если оно не вызывается между PreInit и InitComplete (что звучит именно так, как вы хотите).

Как последний вариант, вы можете быть хитрым и использовать отражение, чтобы получить доступ к свойству Control.ControlState (которое вводит в заблуждение, поскольку оно не связано с Control State - что-то похожее на View State). Это свойство отслеживает элемент управления по ходу его жизненного цикла и имеет следующие значения:

internal enum ControlState
{
    Constructed,
    FrameworkInitialized,
    ChildrenInitialized,
    Initialized,
    ViewStateLoaded,
    Loaded,
    PreRendered
}

Вы заметите, что Enum является внутренним. Так же и свойство Control.ControlState. Но с Reflection вы можете использовать это - и вы можете даже использовать его из метода расширения, который является внешним по отношению к странице.

Надеюсь, один из этих способов сработает для вас!

0 голосов
/ 10 августа 2011

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

Просто вызовите метод PrependTitle в page_load каждой mashterpage и страницы и добавьте текстк названию.

0 голосов
/ 09 августа 2011

Лучше всего использовать ключевое слово Handles , чтобы прикрепить метод к событию.

Возможно, вам придется создать подкласс System.Web.UI.Page, чтобы обеспечить это.

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