Get click event from linkbutton in compositecontrol in Web Forms - asp.net

I have created a composite control which houses a number of tiles (which are also custom controls). In my web page I want to catch the click-event of a tile, but I can't figure out how.
This is the TileButton: (the components can be designed dynamically, but I left this part out to keep it simple)
public class TileButton : LinkButton
{
public string Title { get; set; }
public string ImageUrl { get; set; }
private System.Web.UI.WebControls.Label title =
new System.Web.UI.WebControls.Label();
private Image image = new Image();
protected override void CreateChildControls()
{
base.CreateChildControls();
title.Text = Title;
image.ImageUrl = ImageUrl;
Controls.Add(title);
Controls.Add(image);
}
protected override void RenderContents(HtmlTextWriter writer)
{
RenderTitle(writer);
RenderImage(writer);
}
private void RenderImage(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class,
"some css classes");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
image.RenderControl(writer);
writer.RenderEndTag();
}
private void RenderTitle(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class,
"other css classes");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.AddAttribute(HtmlTextWriterAttribute.Class,
"title css classes");
writer.RenderBeginTag(HtmlTextWriterTag.H6);
title.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
}
}
This is the composite control:
public class TilesControl : CompositeDataBoundControl
{
public List<TileButton> TileButtons { get; set; } =
new List<TileButton>();
protected override int CreateChildControls(IEnumerable datasource, bool databinding)
{
base.CreateChildControls();
int count = 0;
foreach (var item in datasource)
{
var tileButton = item as TileButton;
tileButton.ID = "tile" + count;
Controls.Add(tileButton);
TileButtons.Add(tileButton);
count++;
}
return count;
}
protected override void Render(HtmlTextWriter writer)
{
AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Class, "some css classes");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
foreach (var tile in TileButtons)
{
tile.CssClass = "button css classes";
tile.RenderControl(writer);
}
writer.RenderEndTag();
}
}
And in the page it's included like this:
<Something:TilesControl runat="server" ID="tiles1" DataSourceID="source1"></Something:TilesControl>
It all renders perfectly, the datasource is bound, but now I want the code behind to do something when a tileButton is clicked.
Extra: I would like the TileButton to have a property that defines WHAT to do when the button is clicked (some type of delegate?). Any pointers on that?
Thanks a lot.

It looks like you are binding a List<TileButton> as the DataSource of TilesControl. So you can bind a Click event to one of those buttons in the List before you bind them as the DataSource.
protected void Page_Load(object sender, EventArgs e)
{
//create a new tilescontrol instance
TilesControl tc = new TilesControl();
//create a list of tilebuttons
List<TileButton> buttons = new List<TileButton>();
//add some buttons for testing
for (int i = 0; i < 10; i++)
{
TileButton b = new TileButton();
b.ID = "TileButton" + i;
b.Title = "TileButton " + i;
//add the click event of a button here
b.Click += TileButton_Click;
//add the button to the list
buttons.Add(b);
}
//bind the list of buttons to the tilescontrol
tc.DataSource = buttons;
tc.DataBind();
//add the tilescontrol to the page
PlaceHolder1.Controls.Add(tc);
}
private void TileButton_Click(object sender, EventArgs e)
{
//display results
Label1.Text = ((TileButton)sender).Title + " Clicked!";
}

Related

IsHandleCreated Prop. is always false for gridview control in dev express

My windows form contains ​DevExpress.XtraGrid.GridControl on Form1 similar way there is also 2nd class called it as Form2. On Form1 I am loading data from database. When I double click on grid row it assigns to an Form2. on Form1 gridControl1_DoubleClick event IsHandleCreated prop is true (Form2 is Inherited from Form1)
void gridControl1_DoubleClick(object sender, EventArgs e)
{
if (gridControl1.IsHandleCreated)
{
}
Form2 obj = new Form2();
obj.Display();
}
so I have created one property like on Form1
public GridControl GridControl1
{
get { return gridControl1; }
}
but when I call the Display() method of Form2 and check the IsHandleCreated prop on Form2 is false.
public void Display()
{
if (handleCreated)
{
}
}
complete code as below **Form1**
public partial class Form1 : Form
{
public GridControl GridControl1
{
get { return gridControl1; }
}
public bool handleCreated
{
get { return gridControl1.IsHandleCreated; }
}
public Form1()
{
InitializeComponent();
gridControl1.DataSource = CreateTable(20);
gridControl1.DoubleClick += gridControl1_DoubleClick;
}
void gridControl1_DoubleClick(object sender, EventArgs e)
{
if (gridControl1.IsHandleCreated)
{
}
Form2 obj = new Form2();
obj.Display();
}
private DataTable CreateTable(int rowCount)
{
DataTable table = new DataTable();
table.Columns.Add("String", typeof(string));
table.Columns.Add("Int", typeof(int));
table.Columns.Add("Date", typeof(DateTime));
for (var i = 0; i < rowCount; i++)
{
table.Rows.Add(string.Format("Row {0}", i), i, DateTime.Today.AddDays(i));
}
return table;
}
}
**Form2**
public class Form2 : Form1
{
public Form2()
{
}
public void Display()
{
if (handleCreated)
{
}
//Form1 obj = new Form1();
//if (obj.handleCreated)
//{
//}
}
}
In Form2 handleCreated its always false I dont know why?
please help me
This is because your form2 object is just only initialized. Control will get its handle only after window is created, which displays this control. So, you need to call form2.Show() or form2.ShowDialog() and after that check for gridControl1.IsHandleCreated.
You can simply test this behavior by using this code:
Form2 obj = new Form2();
MessageBox.Show("Created: " + obj.handleCreated);
obj.Show();
MessageBox.Show("Shown: " + obj.handleCreated);

How to implement search functionality with repeater?

I have an aspx page like this:
<asp:TextBox ID="SearchInput" AutoPostBack="true" runat="server" />
<asp:Repeater ID="SelectUserListItemRepeater" runat="server">
<ItemTemplate>
<div><%# DataBinder.Eval(Container.DataItem, "Title")%></div>
</ItemTemplate>
</asp:Repeater>
And code behind like this.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Test : UserControl
{
private IList<TestItem> items;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
items = new List<TestItem>();
items.Add(new TestItem { Title="Lars"});
items.Add(new TestItem { Title = "Johan" });
items.Add(new TestItem { Title = "Bob" });
SelectUserListItemRepeater.DataSource = items;
SelectUserListItemRepeater.DataBind();
SearchInput.TextChanged += new EventHandler(SearchInput_TextChanged);
}
void SearchInput_TextChanged(object sender, EventArgs e)
{
var input = sender as TextBox;
var searchResult = items.Where(i => i.Title.Contains(input.Text));
/* Here I would like to show this search result in the Repeater,
* but what is the best way to do it?
*/
}
}
public class TestItem {
public string Title { get; set; }
}
What is to best way to implement search functionality in this kind of situation? I have one search text input and one repeater which renders a list of strings in DIV elements. When user writes some search key in a input then the repeater should only show those strings which contains the search key? How can I hide other RepeaterItems which doesn't contains the search key? or should I remove those RepeaterItems some how?
Try this:
void SearchInput_TextChanged(object sender, EventArgs e)
{
var input = sender as TextBox;
var searchResult = items.Where(i => i.Title.Contains(input.Text));
SelectUserListItemRepeater.DataSource = searchResult;
SelectUserListItemRepeater.DataBind();
}
Try this
private static List<TestItem> items = new List<TestItem>();
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
items = new List<TestItem>();
items.Add(new TestItem { Title="Lars"});
items.Add(new TestItem { Title = "Johan" });
items.Add(new TestItem { Title = "Bob" });
SearchInput.TextChanged += new EventHandler(SearchInput_TextChanged);
// bind repeater.
BindRepeater();
}
protected void SearchInput_TextChanged(object sender, EventArgs e)
{
var input = sender as TextBox;
items = items.Where(i => i.Title.Contains(input.Text)).ToList();
BindRepeater();
}
private void BindRepeater()
{
SelectUserListItemRepeater.DataSource = items;
SelectUserListItemRepeater.DataBind();
}

showing submit query after deleting the image from datalist

I have the following code and some images listed in a DataList:
protected void btnDel_Click(object sender, EventArgs e)
{
if (Id != 0)
{
BaseClass.Delete(Id1);
string path = Path.Combine(GetDirectory(Name), Name);
File.Delete(path);
}
}
public void BindImages()
{
path = BaseClass.GetAllImages(PId);
for (int i = 0; i < path.Count; i++)
{
ArrayList lst = path[i];
tb.Rows.Add(Convert.ToInt32(lst[0]), lst[1].ToString(),
lst[2].ToString(), i);
}
dlst1.DataSource = tb;
dlst1.DataBind();
}
When I click on the delete button for an image the image is removed but when I rebind the DataList the images are being duplicated.
I am binding the DataList in my PageLoad method.
You have to use IsPostBack boolean property in the Page_Load handler.
protected void page_load()
{
if(!IsPostBack)
{
BindImages();
}
}

The problem when loading a web user control dynamicly

The web user control: FilterLabel
<span style=" display:block; float:left; margin:5px; padding: 5px; border: 1px inset #000000; font-family: Tahoma; font-size: small;">
<asp:Label ID="lblFilterDisplay" runat="server" Text="Product/Service: This is a testing"></asp:Label>
<asp:ImageButton ID="btnRemove" runat="server" ImageUrl="~/Images/remove.png" OnClick="btnRemove_Click" />
And the part of behind codes for this web user control:
public event EventHandler RemoveClick;
......
public void btnRemove_Click(object sender, EventArgs e)
{
if (RemoveClick != null)
RemoveClick(this, EventArgs.Empty);
}
Next, the web user control "FilterLabel" will be used in another web user control "FilterList":
<%# Register TagPrefix="uc" TagName="FilterLabel" Src="~/Controls/FilterLabel.ascx" %>
<asp:Panel ID="FilterList" runat="server" Width="100%" GroupingText="Filter List" CssClass="filterList">
</asp:Panel>
And the part of behind codes of this web user control is:
protected override void OnInit(EventArgs e)
{
if (IsPostBack)
{
BindFilters();
}
}
public void BindFilters()
{
List<FilterLabel> filters = Filters;
foreach (FilterLabel filter in filters)
{
FilterList.Controls.Add(filter);
}
}
public List<FilterLabel> Filters
{
get
{
List<FilterLabel> filters = Session["Filters"] as List<FilterLabel>;
if (filters == null)
{
filters = new List<FilterLabel>();
}
return filters;
}
}
public void AddFilter(string filterName, string filterContent, string filterValue = null)
{
FilterLabel filter = LoadControl("~/Controls/FilterLabel.ascx") as FilterLabel;
filter.ID = "Filter";
filter.FilterContent = filterContent;
filter.FilterName = filterName;
filter.Value = filterValue;
filter.RemoveClick += new EventHandler(RemoveFilter);
List<FilterLabel> filters = Filters;
filters.Add(filter);
Session["Filters"] = filters;
BindFilters();
}
private void RemoveFilter(object sender, EventArgs e)
{
//some handling codes
}
So now the problem is the btnRemove_Click event isn't activated when I click the image button "btnRemove".
You should try with bubble event. with your solution you will need on each postback to rebind event handler on each usercontrol for existing filters
public int FilterCount
{
get{
if(ViewState["filter_count"] == 0){
FilterCount = 0;
}
return (int)ViewState["filter_count"];
}
set{
ViewState["filter_count"] = value;
}
}
protected void RecreateFilterControlls()
{
for(int i =0; i < FilterCount; i++){
FilterLabel filter = LoadControl("~/Controls/FilterLabel.ascx") as FilterLabel;
FilterList.Controls.Add(filter);
filter.RemoveClick += new EventHandler(RemoveFilter);
}
}
protected override void OnInit(EventArgs e)
{
if (IsPostBack)
{
RecreateFilterControlls();
}
}
// this is for button which will add new FilterLabel UserControl
protected void AddNewFilter_Click(object sender, EventArgs e)
{
// just create filter
AddFilter(<FilterNameTextBox|combobox>, <FilterContentTextBox>, <filterValue>);
}
public void AddFilter(string filterName, string filterContent, string filterValue = null)
{
FilterLabel filter = LoadControl("~/Controls/FilterLabel.ascx") as FilterLabel;
filter.ID = "Filter";
filter.FilterContent = filterContent;
filter.FilterName = filterName;
filter.Value = filterValue;
filter.RemoveClick += new EventHandler(RemoveFilter);
// increament filter count
FilterCount++;
}
private void RemoveFilter(object sender, EventArgs e)
{
//some handling codes
//remove control which caused this event
FilterList.Controls.Remove(sender); // or you will need to ask for IndexOf(sender);
FilterCount--;
}
the rest will be handled by ViewState it self, so you don't need to bind data back to FilterLabel back

Disable a checkbox created at runtime

In my asp.net application i have created checkboxes at runtime. I want to disable the checked checkbox when i click on a button. How do I achieve this? Here is my code:
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 12; i++)
{
tr = new TableRow();
tr.BorderStyle = BorderStyle.Groove;
for (int j = 0; j < 18; j++)
{
tc = new TableCell();
tc.BorderStyle = BorderStyle.Groove;
ch = new CheckBox();
tc.Controls.Add(ch);
tr.Cells.Add(tc);
}
Table1.Rows.Add(tr);
}
if(!IsPostBack)
{
form1.Controls.Add(ch);
mRoleCheckBoxList.Add("RoleName", ch);
}
}
protected void Button1_Click(object sender, EventArgs e)
{
IDictionaryEnumerator RoleCheckBoxEnumerator = mRoleCheckBoxList.GetEnumerator();
while (RoleCheckBoxEnumerator.MoveNext())
{
CheckBox RoleCheckBox = (CheckBox)RoleCheckBoxEnumerator.Value;
string BoxRoleName = (string)RoleCheckBox.Text;
if (RoleCheckBox.Checked == true)
{
RoleCheckBox.Enabled = false;
break;
}
}
}
One rule-of-thumb while dealing with dynamically generated user controls is that you have to add them to the container on EVERY POSTBACK.
Just modify your code to generate the controls on every postback, and your code will start working like a charm!
EDIT
I am unsure what the ch variable is. I have assumed that its a checkbox. If I am correct, then all you have to do is to modify these lines
if(!IsPostBack)
{
form1.Controls.Add(ch);
mRoleCheckBoxList.Add("RoleName", ch);
}
to this
//if(!IsPostBack)
{
form1.Controls.Add(ch);
mRoleCheckBoxList.Add("RoleName", ch);
}
EDIT 2
This is the code for generating 10 checkboxes dynamically -
protected void Page_Init(object sender, EventArgs e)
{
CheckBox c = null;
for (int i = 0; i < 10; i++)
{
c = new CheckBox();
c.ID = "chk" + i.ToString();
c.Text = "Checkbox " + (i + 1).ToString();
container.Controls.Add(c);
}
}
Check the checkboxes when the page renders on the client side, click the button. This will cause a postback and the checkboxes will be generated again. In the click event of the button, you'll be able to find the checkboxes like this -
protected void Button1_Click(object sender, EventArgs e)
{
CheckBox c = null;
for (int i = 0; i < 10; i++)
{
c = container.FindControl("chk" + i.ToString()) as CheckBox;
//Perform your relevant checks here, and disable the checkbox.
}
}
I hope this is clear.
Maybe
RoleCheckBox.Parent.Controls.Remove(RoleCheckBox);
You are not getting a proper reference to your checkboxes - mRoleCheckBoxList is not mentioned as part of your checkbox creation.
Try the following in your button event handler:
foreach (TableRow row in Table1.Rows)
foreach (TableCell cell in row.Cells)
{
CheckBox check = (CheckBox)cell.Controls[0];
if (check.Checked) check.Enabled = false;
}
Always when creating dynamic controls in .Net create them here:
protected override void CreateChildControls()
{
base.CreateChildControls();
this.CreateDynamicControls();
} //eof method
and in the PostBack find the them either from the event trigger or from a non-dynamic control:
/// <summary>
/// Search for a control within the passed root control by the control id passed as string
/// </summary>
/// <param name="root">the upper control to start to search for</param>
/// <param name="id">the id of the control as string</param>
/// <returns></returns>
public virtual Control FindControlRecursively(Control root, string id)
{
try
{
if (root.ID == id)
{
return root;
} //eof if
foreach (Control c in root.Controls)
{
Control t = this.FindControlRecursively( c, id);
if (t != null)
{
return t;
} //eof if
} //eof foreach
} //eof try
catch (Exception e)
{
return null;
} //eof catch
return null;
} //eof method

Resources