Usuário com melhor resposta
Controle Adicionado "Dinamicamente", inicializado no método "OnInit" não dispara eventos

Pergunta
-
Bom dia,
escrevi estas classes (que derivam de várias outras e implementam diversas interfaces que escrevi) porém, mesmo iniciando o controle "filho" no método sobrescrito "OnInit", e atribuindo neste momento o evento ao controle, o mesmo não dispara o evento associado. Nenhum dos 3 itens propostos (2 botões e 1 REPEATER!!).
Por favor, vejam o código abaixo (PS: Muitos namespaces aparecerão - estes são próprios).
namespace Info { public sealed class StringArrayConverter : Sys.ComponentModel.TypeConverter //http://stackoverflow.com/questions/116797/passing-int-array-as-parameter-in-web-user-control { public override bool CanConvertFrom(Sys.ComponentModel.ITypeDescriptorContext context, Sys.Type sourceType) { return sourceType == typeof(string); } private string[] Spliter(string value) { if (value == null || value == "") { return new string[] { }; } else { return value.Split(new string[] { "||" }, Sys.StringSplitOptions.RemoveEmptyEntries); } } public override object ConvertFrom(Sys.ComponentModel.ITypeDescriptorContext context, Sys.Globalization.CultureInfo culture, object value) { return this.Spliter(value as string); } } public class Template : SysWeb.UI.ITemplate //https://msdn.microsoft.com/en-us/library/aa289501(v=vs.71).aspx { public string IdFieldName { get; set; } public string LabelFieldName { get; set; } protected void Label_DataBinding(object sender, Sys.EventArgs e) { SysWCt.Literal nLc = (SysWCt.Literal)sender; nLc.Text += NFlds.String.Read((SysWCt.RepeaterItem)nLc.NamingContainer, this.LabelFieldName); } private void Button_DataBinding(object sender, Sys.EventArgs e) { MdWeb.Controls.Button nBt = (MdWeb.Controls.Button)sender; nBt.CommandArgument = NFlds.Integer.Read((SysWCt.RepeaterItem)nBt.NamingContainer, this.IdFieldName); } protected SysWCt.Literal CreateLiteral(string Text, bool Handled) { SysWCt.Literal nLc = new SysWCt.Literal(); nLc.Text = Text; if (Handled) { nLc.DataBinding += this.Label_DataBinding; } return nLc; } protected MdWeb.Controls.Button CreateButton(string Name, MdWeb.Controls.Button.Behaving Behave) { MdWeb.Controls.Button nBt = new MdWeb.Controls.Button(); nBt.ID = Name; nBt.CommandName = Name; nBt.Behave = Behave; nBt.DataBinding += this.Button_DataBinding; return nBt; } public void InstantiateIn(SysWeb.UI.Control Container) { Container.Controls.Add(this.CreateLiteral("<li><div class=\"control\">", false)); Container.Controls.Add(this.CreateButton(MdWeb.Controls.PickerSearch.SelectKey, MdWeb.Controls.Button.Behaving.IcoSelect)); Container.Controls.Add(this.CreateButton(MdWeb.Controls.PickerSearch.DeleteKey, MdWeb.Controls.Button.Behaving.IcoDelete)); Container.Controls.Add(this.CreateLiteral("</div><div>", false)); Container.Controls.Add(this.CreateLiteral("<b>" + MdCORE.Labels.Front.Item + ":</b>", true)); Container.Controls.Add(this.CreateLiteral("</div></li>", false)); } public Template(string IdFieldName, string LabelFieldName) { this.IdFieldName = IdFieldName; this.LabelFieldName = LabelFieldName; } } public abstract class Panel<TRec, TTarget> : SysWeb.UI.Control, MdWeb.Pages.Blocks.IDependent, SysWeb.UI.IPostBackDataHandler where TRec : NRecs.Parent, NRecs.ILabeled, NRecs.IParented<TTarget>, new() where TTarget : NRecs.Record, new() { public MdWeb.Pages.WebPage MainPage { get { return (MdWeb.Pages.WebPage)this.Page; } } public MdCORE.User SData { get { return this.MainPage.SData; } } public void Alert(string Message) { MdWeb.WebObject.Alert(Message, this.Page); } public bool Alert(bool TestToExit, string Message) { return MdWeb.WebObject.Alert(TestToExit, Message, this.Page); } public abstract string Label { get; } public event MdWeb.Pages.Blocks.BackEventHandler Back; private const string PickerID = "Picker"; private const string AddButtonID = "AddButton"; private const string BackButtonID = "BackButton"; private const string RootKey = "root"; private const string RecKey = "rec"; private const string DataKey = "dtable"; [Sys.ComponentModel.TypeConverter(typeof(MdWeb.Pages.Info.StringArrayConverter))] public string[] Labels { get; set; } public decimal Selected { get { return (decimal)this.ViewState[MdWeb.Pages.Info.Panel<TRec, TTarget>.RootKey]; } set { this.ViewState[MdWeb.Pages.Info.Panel<TRec, TTarget>.RootKey] = value; } } public TRec Record { get { return (TRec)this.ViewState[MdWeb.Pages.Info.Panel<TRec, TTarget>.RecKey]; } } public SysDt.DataTable Data { get { return (SysDt.DataTable)this.ViewState[MdWeb.Pages.Info.Panel<TRec, TTarget>.DataKey]; } set { this.ViewState[MdWeb.Pages.Info.Panel<TRec, TTarget>.DataKey] = value; } } private SysClG.Dictionary<string, MdWeb.Controls.Generic.FieldControl> ChildControls { get; set; } private void InvokeBack() { if (this.Back != null) { this.Back(); } } protected MdWeb.Controls.PickerSearch Picker; protected MdWeb.Controls.Button AddNew; protected MdWeb.Controls.Button BackButton; void SysWeb.UI.IPostBackDataHandler.RaisePostDataChangedEvent() { /* NOTHING */ } public virtual void PostBackLoad() { /* NOTHING */ } public virtual void CreateForm() { /* NOTHING */ } public abstract void SaveData(); protected virtual bool LabelsMatch() { return (this.Labels != null && this.Labels.Length == (this.Record.Count() - 1)); } //'-1 due to root key private void CreateControl<TControl>(TControl Control, string Name, int Pos, bool LabelsMatched) where TControl : MdWeb.Controls.Generic.FieldControl { Control.ID = Name; Control.Label = (LabelsMatched ? this.Labels[Pos] : "Field (" + Pos.ToString() + ")"); this.ChildControls.Add(Name, Control); } private void OnSave(object sender, Sys.EventArgs e) { if (this.Selected != NFlds.Integer.Empty) { ((NRecs.IParented<TTarget>)this.Record).Root.SetValue(this.Selected, true); foreach (SysClG.KeyValuePair<string, MdWeb.Controls.Generic.FieldControl> KeyPair in this.ChildControls) { NFlds.Field Field = this.Record[KeyPair.Key]; if (Field == null) { this.Alert(MdCORE.Labels.Messages.ErrorFieldNotFoundED49); return; } else { Field.Obj = KeyPair.Value.Obj; Field.Postable = KeyPair.Value.Postable; } } if (((NRecs.ILabeled)this.Record).Label == null || ((NRecs.ILabeled)this.Record).Label == "") { this.Alert(MdCORE.Labels.Messages.ErrorNoPostableDataED04); } else { this.SaveData(); } } } private void ClearPanel() { this.Record.Clear(); foreach (SysClG.KeyValuePair<string, MdWeb.Controls.Generic.FieldControl> KeyPair in this.ChildControls) { KeyPair.Value.SetEmpty(); } } private void OnBack(object sender, Sys.EventArgs e) { this.ClearPanel(); this.InvokeBack(); } private void AddTextBox(NFlds.Field Field, int Pos, bool LabelsMatched) { MdWeb.Controls.TextString Box = new MdWeb.Controls.TextString(); this.CreateControl(Box, Field.Name, Pos, LabelsMatched); Pos = (Field as NFlds.String).MaxSize; if (Pos > 0) { Box.MaxLength = Pos; } } private void CreateControls(bool LabelsMatched) { int Pos = 0; string RootName = (this.Record as NRecs.IParented<TTarget>).Root.Name; foreach (NFlds.Field Field in this.Record) { if (Field.Name != RootName) { Sys.Type TypeOf = Field.GetType(); if (TypeOf != typeof(NFlds.Foreign<>) && TypeOf != typeof(NFlds.NullForeign<>) && TypeOf != typeof(NFlds.DateTime) && TypeOf != typeof(NFlds.DblDateTime) && TypeOf != typeof(NFlds.Optional)) { if (TypeOf == typeof(NFlds.Boolean)) { this.CreateControl(new MdWeb.Controls.Check(), Field.Name, Pos, LabelsMatched); } else if (TypeOf == typeof(NFlds.String)) { this.AddTextBox(Field, Pos, LabelsMatched); } else if (TypeOf == typeof(NFlds.Integer) || TypeOf == typeof(NFlds.NullInteger)) { this.CreateControl(new MdWeb.Controls.TextInteger(), Field.Name, Pos, LabelsMatched); } else if (TypeOf == typeof(NFlds.Double) || TypeOf == typeof(NFlds.NullDouble) || TypeOf == typeof(NFlds.Money) || TypeOf == typeof(NFlds.NullMoney)) { this.CreateControl(new MdWeb.Controls.TextDouble(), Field.Name, Pos, LabelsMatched); } else if (TypeOf == typeof(NFlds.Double) || TypeOf == typeof(NFlds.NullDouble)) { this.CreateControl(new MdWeb.Controls.TextDouble(), Field.Name, Pos, LabelsMatched); } else if (TypeOf == typeof(NFlds.Date) || TypeOf == typeof(NFlds.IntDate)) { this.CreateControl(new MdWeb.Controls.TextCalendar(), Field.Name, Pos, LabelsMatched); } else if (TypeOf == typeof(NFlds.DblTime)) { this.CreateControl(new MdWeb.Controls.TextTime(), Field.Name, Pos, LabelsMatched); } Pos++; } } } } private void LoadPanel() { try { foreach (SysClG.KeyValuePair<string, MdWeb.Controls.Generic.FieldControl> Pair in this.ChildControls) { Pair.Value.Obj = this.Record[Pair.Key].Obj; Pair.Value.Postable = false; } } catch { this.ClearPanel(); } } private void LoadPanel(decimal Id) { if (this.Selected != NFlds.Integer.Empty && this.Record.Load(this.MainPage.Dbm, Id)) { this.LoadPanel(); } else { this.ClearPanel(); } } protected virtual void SearchData() { this.Data = NView.View.Search(this.MainPage.Dbm, this.Record, Distinct: false, Limit: 0, WhereArgs: new NView.Where.Args(((NRecs.IParented<TTarget>)this.Record).Root.EqualArg(this.Selected.ToString(), false)), OrderBy: default(NView.OrderBy), Joins: null); } private void OnItemCommand(object source, SysWCt.RepeaterCommandEventArgs e) { decimal Id = MdWeb.Controls.PickerSearch.GetSelection(e); if (Id == NFlds.Integer.Empty) { this.Alert(MdLbl.Messages.ErrorNoIndexED14); } { if (e.CommandName == MdWeb.Controls.PickerSearch.SelectKey) { this.LoadPanel(Id); } else if (e.CommandName == MdWeb.Controls.PickerSearch.DeleteKey) { if (this.SData.Delete<TRec>(this.MainPage.Dbm, this.Record)) { this.ClearPanel(); this.SearchData(); this.Picker.Bind(this.Data); } else { this.Alert(MdLbl.Messages.ErrorDeleteRecordED46); } } else { this.Alert(MdLbl.Messages.ErrorKeyInvalidED27); } } } protected virtual SysWeb.UI.ITemplate CreateItemTemplate() { return new MdWeb.Pages.Info.Template(this.Record.Id.Name, this.Record.Label.Name); } private void CreateUI() { this.Picker = new MdWeb.Controls.PickerSearch(); this.Picker.ItemCommand += this.OnItemCommand; this.Picker.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.PickerID; this.Picker.EnableViewState = true; this.AddNew = new MdWeb.Controls.Button(); this.AddNew.Click += this.OnSave; this.AddNew.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.AddButtonID; this.AddNew.Behave = MdWeb.Controls.Button.Behaving.SaveAction; this.AddNew.Style.Add("margin-right", "6px"); this.AddNew.Style.Add("float", "left"); this.BackButton = new MdWeb.Controls.Button(); this.BackButton.Click += this.OnBack; this.BackButton.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.BackButtonID; this.BackButton.Behave = MdWeb.Controls.Button.Behaving.BackAction; this.ChildControls = new SysClG.Dictionary<string, MdWeb.Controls.Generic.FieldControl>(); } private void BindUI() { this.Picker.ItemTemplate = this.CreateItemTemplate(); this.CreateControls(this.LabelsMatch()); } private void AddViewState(TRec item, decimal Id, SysDt.DataTable DTable) { this.ViewState.Add(MdWeb.Pages.Info.Panel<TRec, TTarget>.RootKey, NFlds.Integer.Empty); this.ViewState.Add(MdWeb.Pages.Info.Panel<TRec, TTarget>.DataKey, new SysDt.DataTable()); this.ViewState.Add(MdWeb.Pages.Info.Panel<TRec, TTarget>.RecKey, item); } private void AddPair(Sys.Collections.ArrayList lst, string Key, object Value) { lst.Add(Key); lst.Add(Value); } protected override void OnInit(Sys.EventArgs e) { this.CreateUI(); if (!this.Page.IsPostBack) { this.AddViewState(new TRec(), NFlds.Integer.Empty, new SysDt.DataTable()); this.BindUI(); } base.OnInit(e); } protected override void OnLoad(Sys.EventArgs e) { base.OnLoad(e); this.DataBind(); } protected override object SaveViewState() { Sys.Collections.ArrayList lst = new Sys.Collections.ArrayList(); this.AddPair(lst, MdWeb.Pages.Info.Panel<TRec, TTarget>.RootKey, this.Selected); this.AddPair(lst, MdWeb.Pages.Info.Panel<TRec, TTarget>.RecKey, this.Record); this.AddPair(lst, MdWeb.Pages.Info.Panel<TRec, TTarget>.DataKey, this.Data); return new SysWeb.UI.Pair(lst, null); } protected override void LoadViewState(object savedState) { try { Sys.Collections.ArrayList lst = ((savedState as SysWeb.UI.Pair).First as Sys.Collections.ArrayList); for (int i = 0; i < lst.Count - 1; i = i + 2) { this.ViewState.Add((string)lst[i], lst[i + 1]); } this.LoadPanel(); this.BindUI(); lst.Clear(); lst = null; this.Picker.Bind(this.Data); } catch { this.Alert(MdCORE.Labels.Messages.ErrorInfoPanelViewStateED50(this.ID)); } } public bool LoadPostData(string postDataKey, global::System.Collections.Specialized.NameValueCollection postCollection) { foreach (string Key in postCollection) { this.ChildControls[Key].Obj = postCollection[Key]; } return true; } public virtual void Clear() { this.Selected = NFlds.Integer.Empty; this.ClearPanel(); } public virtual void LoadSelection() { if (this.Selected != NFlds.Integer.Empty) { this.SearchData(); this.Picker.Bind(this.Data); } else { this.Clear(); } } protected override void Render(SysWeb.UI.HtmlTextWriter writer) { writer.Write("<b>" + this.Label + "</b><br /><div><ul class=\"bindedinfo\">"); this.Picker.RenderControl(writer); writer.Write("</ul></div><div>"); foreach (SysClG.KeyValuePair<string, MdWeb.Controls.Generic.FieldControl> KeyPair in this.ChildControls) { KeyPair.Value.RenderControl(writer); } this.AddNew.RenderControl(writer); this.BackButton.RenderControl(writer); writer.Write("</div>"); } } } public class Processor : MdWeb.Pages.Info.Panel<MdSet.DEV.Components.Processors, MdSet.DEV.Devices> { public override string Label { get { return MdCORE.Labels.Front.Processor; } } public override void SaveData() { this.Record.Save(this.MainPage.Dbm); } }
Desde já agradeço.
Respostas
-
Opa, tudo bom SammuelMiranda?
Vi que vocês já revisaram bastante coisa, e posso estar sendo redundante, mas você já testou acrescentar os eventos de outra forma, por exemplo, acrescentar um método anônimo simples invés do EventHandler pra ver se ocorre o mesmo comportamento, ou então acrescentar o método do EventHandler como um new EventHandler?
protected MdWeb.Controls.Button CreateButton( string Name, MdWeb.Controls.Button.Behaving Behave ) { MdWeb.Controls.Button nBt = new MdWeb.Controls.Button(); nBt.ID = Name; nBt.CommandName = Name; nBt.Behave = Behave; nBt.DataBinding += new EventHandler(this.Button_DataBinding); return nBt; }
Ou então:
protected MdWeb.Controls.Button CreateButton( string Name, MdWeb.Controls.Button.Behaving Behave ) { MdWeb.Controls.Button nBt = new MdWeb.Controls.Button(); nBt.ID = Name; nBt.CommandName = Name; nBt.Behave = Behave; nBt.DataBinding += (s,e) => { MessageBox.Show("Seu evento funcionou!") }; return nBt; }
Enfim, dá uma olhada nesses exemplos, você tem bastante elemento herdando de outras classes nativas e muita coisa criada de forma dinâmica. Em ambientes onde você tem esse grau de complexidade problemas como este podem aparecer, e geralmente é alguma coisa muito simples que resolve, o problema é identificar no emaranhado do fluxo do programa ^^
Boa sorte cara, se eu descobrir alguma coisa eu volto a postar nessa thread.
EDIT: Cara, dá uma olhada na thread dese maluco aqui, acho que o problema era parecido, e a forma como ele resolveu pode te ajudar:
How to add event handlers to dynamic controls
- Editado Samuel Pelaquim sexta-feira, 30 de outubro de 2015 18:21 Colei o link direto, esuqeci que é MSDN...
- Sugerido como Resposta SimorC domingo, 1 de novembro de 2015 22:56
- Marcado como Resposta Marcos SJ segunda-feira, 2 de novembro de 2015 10:52
- Não Marcado como Resposta SammuelMiranda terça-feira, 3 de novembro de 2015 10:37
- Marcado como Resposta SammuelMiranda terça-feira, 3 de novembro de 2015 11:39
-
Tudo Resolvido. Bastou colocar "this.Page.RegisterRequiresPostBack(this);" na primeira linha no "OnInit()" e ajustar o método "LoadPostData" para pegar as chaves certas. Tudo correto, graças ao input do chara. Obrigado Samuel.
public bool LoadPostData(string postDataKey, global::System.Collections.Specialized.NameValueCollection postCollection) { postDataKey += this.IdSeparator; foreach (SysClG.KeyValuePair<string, MdWeb.Controls.Generic.FieldControl> KeyPair in this.ChildControls) { KeyPair.Value.Obj = postCollection[postDataKey + KeyPair.Key]; } return true; }
Além disso, no método "CreateControls()" coloquei "this.Controls.Add(Control)" também, ficou assim:
private void CreateControl<TControl>(TControl Control, string Name, int Pos, bool LabelsMatched) where TControl : SysWeb.UI.Control, MdWeb.Controls.Generic.FieldControl { Control.ID = Name; Control.Label = (LabelsMatched ? this.Labels[Pos] : "Field (" + Pos.ToString() + ")"); this.ChildControls.Add(Name, Control); this.Controls.Add(Control); }
- Marcado como Resposta SammuelMiranda terça-feira, 3 de novembro de 2015 11:39
Todas as Respostas
-
Boa tarde Sammuel,
Você debugando o código conseguiu navegar pelos métodos?
De uma olhada nesse exemplo: Utilizando delegates e eventos com user controls
-
Boa tarde, SammuelMiranda.
Olhando o código ficou uma dúvida.
Os botões que não estão disparando eventos são esses:
Container.Controls.Add(this.CreateButton(MdWeb.Controls.PickerSearch.SelectKey, MdWeb.Controls.Button.Behaving.IcoSelect)); Container.Controls.Add(this.CreateButton(MdWeb.Controls.PickerSearch.DeleteKey, MdWeb.Controls.Button.Behaving.IcoDelete));
Ou esses:
this.AddNew = new MdWeb.Controls.Button(); this.BackButton = new MdWeb.Controls.Button();
Att., Rafael Simor
-
-
-
Bom, tenho algumas ideias:
- Como o Roberto já havia falado, coloque um breaking point no teu OnInit() e dê F10/F11, verificando linha por linha; para melhor entender o problema.
- Verifique se a ViewState da Page/UserControl (até mesmo web.config) está como true.
- Verifique se os eventos não estão se perdendo no PostBack.
- Verifique pelo debugger do navegador se não está gerando nenhum erro ao clicar no botão.
- Verifique se os ID's gerados dos controles estão corretos.
- Verifique se os Behaviors desses controles estão corretamente configurados.
Pessoalmente, se nada desse certo, eu criaria um UserControl de "teste", adicionando os controles dinamicamente (nativos do ASP.NET); colocaria um breaking point e compararia os valores de ambos formulários, verificando se não existe alguma discrepância muito grande nas propriedades da Página e dos Controles.
Att., Rafael Simor
-
SimorC, bom dia.
Ponto a ponto:
- Já fiz o break point no OnInit(): o OnInit() é executado, chama o metodo "CreateUI()" (que cria o Repeater e os botões e associa eventos a eles). Esses eventos não são disparados no entanto, o que é o meu problema (já botei break nos handlers deles).
- O ViewState está "funcionando" corretamente. Os métodos "SaveViewState()" e "LoadViewState()" são chamados e executados restaurando as chaves que criei. Os controles são criados novamente no "OnInit()", antes do ViewState ser carregado pois os controles não ficam gravados no ViewState.
- Como verifico se o evento se "perdeu" no Postback?
- Todos os controles são criados, com MESMO ID sempre, no método "CreateUI()", ativado durante o "OnInit()".
- Behavior é uma propriedade que eu criei, que é basicamente uma substituição do atributo "CssClass", apenas para eu não ter que digitar a classe CSS do botão, facilitando os filtros.
Esse código deriva de UserControl já. Deriva de uma classe que deriva do UserControl. Fiz isso apenas para disponibilizar mais métodos a todos os meus UserControls, com "Alert(string)" ... nada que afete os eventos ou Init ou Load do controle.
-
Bom dia, SammuelMiranda.
Poderia nos informar se os botões estão ao menos disparando o PostBack?
Este UserControl está sendo utilizado dentro de um UpdatePanel?
Outra ideia:
- Coloque esta linha do evento OnInit() no começo, não no final:
base.OnInit(e);
Att., Rafael Simor
-
Você se refere a essa parte:
protected override void OnInit(Sys.EventArgs e) { this.CreateUI(); if (!this.Page.IsPostBack) { this.AddViewState(new TRec(), NFlds.Integer.Empty, new SysDt.DataTable()); this.BindUI(); } base.OnInit(e); }
Se sim, já tentei o "base.OnInit(e);" no começo (primeira chamada do método) mas mesmo assim sem sucesso. Agora não, ele não está dentro de um UpdatePanel, está em uma Page (System.Web.Page).
Agora quanto ao Postback, não entendi sua pergunta. Não, ele não dispara no postback, nem mesmo o método "bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)" está sendo acionado...
-
Boa tarde.
Poderias tentar criar o botão diretamente no OnInit()?
Algo do tipo:
protected override void OnInit(Sys.EventArgs e) { // TODO: Coloque um breaking point aqui para verificar se o botão está ao menos gerando Postback base.OnInit(e); Button btnTeste = new Button { Text = "Testar" }; btnTeste.Click += btnTeste_OnClick; // TODO: Adicionar botão na página //this.CreateUI(); //if (!this.Page.IsPostBack) //{ // this.AddViewState(new TRec(), NFlds.Integer.Empty, new SysDt.DataTable()); // this.BindUI(); //} } protected void btnTeste_OnClick(object sender, EventArgs e) { // TODO: Coloque um breaking point neste evento somente para ver se ele será chamado }
Vamos tentar fazer funcionar do jeito mais simples possível. Se funcionar, deve ser algum problema de lógica (ordem de criação dos controles, possivelmente). Se não funcionar, é provável que o problema esteja no container (como a página está tratando os Postbacks, algum Id/ViewState que a página não esteja mantendo, etc.).
Att., Rafael Simor
-
Oi SimorC, então o método "CreateUI()" faz isso:
private void CreateUI() { this.Picker = new MdWeb.Controls.PickerSearch(); this.Picker.ItemCommand += this.OnItemCommand; this.Picker.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.PickerID; this.Picker.EnableViewState = true; this.AddNew = new MdWeb.Controls.Button(); this.AddNew.Click += this.OnSave; this.AddNew.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.AddButtonID; this.AddNew.Behave = MdWeb.Controls.Button.Behaving.SaveAction; this.AddNew.Style.Add("margin-right", "6px"); this.AddNew.Style.Add("float", "left"); this.BackButton = new MdWeb.Controls.Button(); this.BackButton.Click += this.OnBack; this.BackButton.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.BackButtonID; this.BackButton.Behave = MdWeb.Controls.Button.Behaving.BackAction; this.ChildControls = new SysClG.Dictionary<string, MdWeb.Controls.Generic.FieldControl>(); }
e ele é chamado no método sobrescrito "OnInit()" da classe abstrata "Panel<>" assim:
protected override void OnInit(Sys.EventArgs e) { this.CreateUI(); if (!this.Page.IsPostBack) { this.AddViewState(new TRec(), NFlds.Integer.Empty, new SysDt.DataTable()); this.BindUI(); } base.OnInit(e); }
já tirei o código do "CreateUI()" e escrevi direto no "OnInit()" como você sugeriu e já coloquei breakpoints em ambos os métodos "Click" e "ItemCommand" e no "OnInit". O "OnInit" breca e debuga, mas ele NUNCA DISPARA o "Click" ou "ItemCommand". Exemplo, o botão "BackButton" é associoado ao método "OnBack" descrito por:
private void OnBack(object sender, Sys.EventArgs e) { this.ClearPanel(); this.InvokeBack(); }
Um breakpoint nesse método NUNCA é acessado pelo debug.
-
Pois então, Sammuel, já havia percebido que os métodos criavam os controles e tudo o mais, porém, para identificar o problema, é melhor reduzir um pouco o "escopo", digamos assim.
Colocando um botão extremamente simples direto no OnInit() e verificando que nem mesmo assim os eventos (no caso, btnTeste_OnClick) funcionam, conseguimos saber que o problema não está no "caminho" que teu código percorre.
A maioria dos erros que eu não faço nem ideia do que está acontecendo eu tento simplificar ao máximo. Normalmente consigo identificar mais facilmente.
Criei um exemplo aqui que funciona tranquilamente:
UserCtrl.ascx.cs
namespace AspNetDynamicControlEvents { public partial class UserCtrl : System.Web.UI.UserControl { protected void Page_Load(object sender, EventArgs e) { } protected void Page_Init(object sender, EventArgs e) { Button btnTest = new Button { Text = "Do it for glory" }; btnTest.Click += btnTeste_OnClick; pnlControls.Controls.Add(btnTest); } protected void btnTeste_OnClick(object sender, EventArgs e) { lblTest.Text += " go "; } } }
UserCtrl.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="UserCtrl.ascx.cs" Inherits="AspNetDynamicControlEvents.UserCtrl" %> <asp:Panel ID="pnlControls" runat="server"></asp:Panel> <asp:Label ID="lblTest" runat="server" Text=""></asp:Label>
Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AspNetDynamicControlEvents.Default" EnableViewState="true" %> <%@ Register Src="~/UserCtrl.ascx" TagPrefix="uc1" TagName="UserCtrl" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <uc1:UserCtrl runat="server" id="UserCtrl" /> </div> </form> </body> </html>
Default.aspx.cs
namespace AspNetDynamicControlEvents { public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } } }
Web.config
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> </configuration>
Provavelmente com mais controles dinâmicos seja interessante tratar os ID's também, porém, do jeito que estou fazendo, no momento, funciona sem problemas aqui; recomendo tentar, como falei, do jeito mais simples e ir complementando com o tempo para ver onde o código vai "quebrar" (isso se pelo debug não for possível identificar).
Att., Rafael Simor
-
Ok SimorC, legal. Eu também costumo testar coisas com o mínimo de código possível, e devo ter falhado em explicar algo... esse controle é TOTALMENTE programado, não existe um arquivo ASCX correspondente. O botão por exemplo, ele deriva do "System.Web.UI.WebControls.Button" e apenas adiciona um propriedade (Behavior) - mesmo se eu trocar por um Button convencional o problema é o mesmo.
Esse controle vai direto na página ASPX. Assim:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CWEB.Web.DefaultPage" EnableViewState="true" %> <%@ Register TagPrefix="CNT" TagName="CONTROLS" Namespace="CWEB.Info" Assembly="CWEB" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <CNT:Processor runat="server" id="UserCtrl" Labels="Model||Brand" /> </div> </form> </body> </html>
-
Olá SammuelMiranda,
tudo bem?
O problema já foi solucionado?
Marcos Roberto de Souza Junior
Esse conteúdo e fornecido sem garantias de qualquer tipo, seja expressa ou implícita
MSDN Community Support
Por favor, lembre-se de Marcar como Resposta as respostas que resolveram o seu problema. Essa e uma maneira comum de reconhecer aqueles que o ajudaram e fazer com que seja mais fácil para os outros visitantes encontrarem a resolução mais tarde.
-
-
Opa, tudo bom SammuelMiranda?
Vi que vocês já revisaram bastante coisa, e posso estar sendo redundante, mas você já testou acrescentar os eventos de outra forma, por exemplo, acrescentar um método anônimo simples invés do EventHandler pra ver se ocorre o mesmo comportamento, ou então acrescentar o método do EventHandler como um new EventHandler?
protected MdWeb.Controls.Button CreateButton( string Name, MdWeb.Controls.Button.Behaving Behave ) { MdWeb.Controls.Button nBt = new MdWeb.Controls.Button(); nBt.ID = Name; nBt.CommandName = Name; nBt.Behave = Behave; nBt.DataBinding += new EventHandler(this.Button_DataBinding); return nBt; }
Ou então:
protected MdWeb.Controls.Button CreateButton( string Name, MdWeb.Controls.Button.Behaving Behave ) { MdWeb.Controls.Button nBt = new MdWeb.Controls.Button(); nBt.ID = Name; nBt.CommandName = Name; nBt.Behave = Behave; nBt.DataBinding += (s,e) => { MessageBox.Show("Seu evento funcionou!") }; return nBt; }
Enfim, dá uma olhada nesses exemplos, você tem bastante elemento herdando de outras classes nativas e muita coisa criada de forma dinâmica. Em ambientes onde você tem esse grau de complexidade problemas como este podem aparecer, e geralmente é alguma coisa muito simples que resolve, o problema é identificar no emaranhado do fluxo do programa ^^
Boa sorte cara, se eu descobrir alguma coisa eu volto a postar nessa thread.
EDIT: Cara, dá uma olhada na thread dese maluco aqui, acho que o problema era parecido, e a forma como ele resolveu pode te ajudar:
How to add event handlers to dynamic controls
- Editado Samuel Pelaquim sexta-feira, 30 de outubro de 2015 18:21 Colei o link direto, esuqeci que é MSDN...
- Sugerido como Resposta SimorC domingo, 1 de novembro de 2015 22:56
- Marcado como Resposta Marcos SJ segunda-feira, 2 de novembro de 2015 10:52
- Não Marcado como Resposta SammuelMiranda terça-feira, 3 de novembro de 2015 10:37
- Marcado como Resposta SammuelMiranda terça-feira, 3 de novembro de 2015 11:39
-
Oi chara tudo bem?
Gostei da sua resposta, e me deu uma luz realmente - mas ainda não funcionou. Nem o EDIT com o link que você me passou - notei uma coisa, no método "CreateUI()" eu coloquei:
private void CreateUI() { this.Picker = new MdWeb.Controls.PickerSearch(); if (this.Parent == null || this.Picker.Parent == null) { return; } this.Picker.ItemCommand += new SysWCt.RepeaterCommandEventHandler(this.OnItemCommand); this.Picker.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.PickerID; this.Picker.EnableViewState = true; this.AddNew = new MdWeb.Controls.Button(); this.AddNew.Click += new Sys.EventHandler(this.OnSave); this.AddNew.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.AddButtonID; this.AddNew.Behave = MdWeb.Controls.Button.Behaving.SaveAction; this.AddNew.Style.Add("margin-right", "6px"); this.AddNew.Style.Add("float", "left"); this.BackButton = new MdWeb.Controls.Button(); this.BackButton.Click += new Sys.EventHandler(this.OnBack); this.BackButton.ID = MdWeb.Pages.Info.Panel<TRec, TTarget>.BackButtonID; this.BackButton.Behave = MdWeb.Controls.Button.Behaving.BackAction; this.ChildControls = new SysClG.Dictionary<string, MdWeb.Controls.Generic.FieldControl>(); }
E no teste da propriedade "Parent" o "this.Parent" responde o "ContentPlaceHolder" onde a classe está, mas o "Parent" do "Picker" (objeto criado) responde NULL. Como "Parent" é ReadOnly, como faço para ele assumir o componente "Panel" (principal) como seu "Parent"?
-
Ok, resolvi este problema.
Depois de Criar cada um dos controles tive que chamar "this.Controls.Add(Control)" para cada um deles. Assim a propriedade "Parent" foi definida e os eventos disparados!!!
Meu único problema agora é que, este controle implementa a interface "IPostBackDataHandler", mas o método "bool LoadPostData(string postDataKey, global::System.Collections.Specialized.NameValueCollection postCollection)" nunca é chamado - preciso dele para alimentar os dados preenchidos nos "ChildControls" (um dicionário que criei).
-
Tudo Resolvido. Bastou colocar "this.Page.RegisterRequiresPostBack(this);" na primeira linha no "OnInit()" e ajustar o método "LoadPostData" para pegar as chaves certas. Tudo correto, graças ao input do chara. Obrigado Samuel.
public bool LoadPostData(string postDataKey, global::System.Collections.Specialized.NameValueCollection postCollection) { postDataKey += this.IdSeparator; foreach (SysClG.KeyValuePair<string, MdWeb.Controls.Generic.FieldControl> KeyPair in this.ChildControls) { KeyPair.Value.Obj = postCollection[postDataKey + KeyPair.Key]; } return true; }
Além disso, no método "CreateControls()" coloquei "this.Controls.Add(Control)" também, ficou assim:
private void CreateControl<TControl>(TControl Control, string Name, int Pos, bool LabelsMatched) where TControl : SysWeb.UI.Control, MdWeb.Controls.Generic.FieldControl { Control.ID = Name; Control.Label = (LabelsMatched ? this.Labels[Pos] : "Field (" + Pos.ToString() + ")"); this.ChildControls.Add(Name, Control); this.Controls.Add(Control); }
- Marcado como Resposta SammuelMiranda terça-feira, 3 de novembro de 2015 11:39