2016-03-16 4 views
1

Скажите, что у вас есть пользовательский элемент управления (ASCX):Упорство пользовательский элемент управления (ASCX) EventHandler объект Across постбэков

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Test.ascx.cs" 
    Inherits="WebApplication1.Test" %> 
<asp:Button ID="test" runat="server" OnClick="test_Click" Text="test" /> 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

namespace WebApplication1 
{ 
    public partial class Test : System.Web.UI.UserControl 
    {   
     public event EventHandler Method1; 

     public EventHandler Method2 
     { 
      get { return (EventHandler)Session[this.ClientID + "|Method2"]; } 
      set { Session[this.ClientID + "|Method2"] = value; } 
     } 

     public EventHandler Method3 
     { 
      get { return (EventHandler)ViewState["Method3"]; } 
      set { ViewState["Method3"] = value; } 
     } 

     protected void test_Click(object sender, EventArgs e) 
     { 
      if (Method1 != null) 
       Method1(this, e); 

      if (Method2 != null) 
       Method2(this, e); 

      if (Method3 != null) 
       Method3(this, e); 
     } 
    } 
} 

И у вас есть страницы, которые вы размещаете, что UserControl на:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" 
    AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
    Inherits="WebApplication1._Default" %> 
<%@ Register Src="~/Test.ascx" TagName="Test" TagPrefix="uc1" %> 

<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent"> 
    <uc1:Test ID="TestControl" runat="server" /> 
    <asp:Label ID="Result" runat="server" Text="Test" /> 
</asp:Content> 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

namespace WebApplication1 
{ 
    public partial class _Default : Page 
    { 
     protected void Page_Load(object sender, EventArgs e) 
     { 
      //Uncomment each one to observe their behavior 

      //Will never trigger(unless reset on each postback) 
      //if (!IsPostBack) TestControl.Method1 += new EventHandler(Test); 

      //Will trigger(the code will run) but makes no change to the parent page 
      //if (!IsPostBack) TestControl.Method2 += new EventHandler(Test); 

      /* 
      Will fail because it can't serialize the "EventHandler" object 
      You can play around by changing this to a delegate type 
      and making that serializable, but that fails as well 
      */ 
      //if (!IsPostBack) TestControl.Method3 += new EventHandler(Test); 
     } 
     protected void Test(object sender, EventArgs e) 
     { 
      Result.Text = Guid.NewGuid().ToString(); 
     } 
    } 
} 

Но для этого данного User Control мы хотим определить событие, чтобы зафиксировать щелчок кнопки и вызвать этот триггер для выбора родительского элемента User Control. Также из-за требований, выходящих за рамки этого примера, скажем, что мы хотели бы только когда-либо установить значение «MethodX» EventHandler один раз, т. Е. Не воссоздавать элемент управления/свойство для каждого Postback (в этом примере я демонстрирую эту концепцию только установка события один раз на загрузку страницы).

Как это можно сделать? Все три метода, к которым я попытался провалиться, имеют свои уникальные способы ... Я до сих пор не нашел аналогичного вопроса, связанного с сохранением событий, большинство сообщений посвящено переносу переменных/объектов («Использовать ViewState» или различные другие способы сохранения объектов, не связанных с событиями, см. link) или просто направить пользователя на «воссоздание элемента управления при каждом обратном вызове (включая связанные свойства)», см. link.

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

+0

Элемент управления создается во время инициализации и уничтожается после рендеринга - я бы не рекомендовал его продолжать. Тем не менее, вы можете сохранить состояние элемента управления с помощью ViewState ["State"] = "SOMETHING TO RELOAD TESTCONTROL METHOD", и эта переменная состояния может использоваться для повторного подключения обработчика событий по вашему выбору. –

+0

@BrianMains Интересно, поэтому я говорю, что я могу использовать свойство «State» Viewstate на родительской странице для хранения всего User Control, и это позволит мне сохранить свойство EventHandler, установленное в этом состоянии, или «State», свойство, используемое внутри самого элемента управления, чтобы сохранить свое собственное состояние или состояние EventHandler? Знаете ли вы о каких-либо примерах того, где это было сделано (может быть, пример этого прояснит это предложение)? –

+0

Нет, ViewState не может сохранить элемент управления; поставьте элемент управления на странице, а затем используйте viewstate, чтобы сохранить некоторые флаги, чтобы контролировать, показывает ли UC/скрывает и какие обработчики событий должны быть привязаны и т. д. Он управляет значениями true/false, которые говорят, показывать или скрывать элемент управления , но не сохраняет контроль напрямую. У UC также есть viewstate, поэтому вы можете хранить настройки в UC в своем собственном контейнере viewstate. –

ответ

2

Вам необходимо зарегистрировать события перед событием загрузки (попробуйте инициализировать). Событие триггера события происходит между событиями init и load.

ОБНОВЛЕНИЕ: Извините, вы делаете щелчок правой кнопкой мыши между Load и LoadComplete.

ОБНОВЛЕНИЕ: Я думаю, что нашел то, что вам нужно, и, к сожалению, не может быть того, что вам нужно. Делегат экземпляра нестатического метода сильно зависит от экземпляра класса метода. Каждый запрос, экземпляр страницы создается, и когда конец запроса, он расположен. Страницы не являются одиночными экземплярами. Вот почему, даже если вы храните обработчик в сеансе, его нельзя использовать повторно, потому что он пытается вызвать метод из удаленного экземпляра.

Это хорошая статья о том, как работает события и делегаты: http://csharpindepth.com/Articles/Chapter2/Events.aspx

Самая важная часть заключается в следующем:

[..] ключевые моменты данных в каждом конкретном случае делегата являются метод, на который ссылается делегат, и ссылку на вызов метода on (target). Для статических методов цель не требуется.

Это цели является экземпляром страницы/UserControl страницы первого момента, когда вы создали. Когда вы делаете Postback, экземпляр page/usercontrol изменился, но ваш целевого адресата не был указан.

+0

В соответствии с документацией на [MSDN] (https://msdn.microsoft.com/en-us/library/ms178472.aspx) событие нажатия кнопки в элементе управления происходит между «Load» и «Load», LoadComplete ", это согласуется с поведением, которое наблюдается при отладке элемента управления (когда событие задано при каждой обратной передаче). Присвоение события пользовательскому элементу управления до метода Load (при реализации «Method1» пользовательского элемента управления) не устраняет проблему сохранения события EventHandler. У вас есть пример этого? Возможно, если бы вы включили некоторый код, я мог бы лучше понять ваше решение. –

+0

Извините, вы правы! Тем не менее, я не понимаю, почему вы требуете, чтобы обработчик события не мог быть зарегистрирован в любой обратной передаче. Что не так с этим? –

+0

Хороший вопрос, посмотрите на это [ссылка] (http://stackoverflow.com/questions/18998186/how-to-persist-user-control-values). Эта проблема представляет собой не только стандартные объекты, но и события, как правило, для преодоления этой проблемы вы можете использовать эти подходы [здесь] (http://stackoverflow.com/questions/2646533/how-do-you-persist-a-class -on-postback-in-an-asp-net-3-5-web-forms-project), хорошо для событий, ни один из этих подходов не работает, я должен «зарегистрировать обработчик событий» каждую обратную передачу, а не изящно ... Это вопросы касаются поиска более элегантного/чистого способа, но я не уверен, что это возможно. –

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