I want to set the node colors of a treeview at runtime. I populate the treeview from a collection that has the parentid, childid, and description, and I've added a property representing the color I want applied to the node. FWIW the source is a database, the app is C#.
In a gridview I use RowDataBound() to programmatically affect the control. Im not sure how to do so in the treeview, including which event to use (DataBound()? TreeViewDataBound()?). My research has not been fruitful so far. A code snippet would be very useful.
Hopefully this will give you a raging clue.
When setting a node text, instead of setting
Node Text
set as
<div style='color: red'>Node Text</a>
you can use Prerender event:
protected void TreeView1_PreRender(object sender, EventArgs e)
{
if (IsPostBack) return;
foreach (TreeNode t in TreeView1.Nodes)
{
if (t.Value.EndsWith("1")) //Some Condition
{
string s = t.Text;
string fs = "<span style=\"color: #CC0000\">" + s + "</span>";
t.Text = fs;
}
}
}
Since .NET Framework 4.5 you can use these style properties:
TreeView.LevelStyles Property - represent the node styles at the
individual levels of the tree
TreeView.RootNodeStyle Property
TreeView.ParentNodeStyle Property
TreeView.LeafNodeStyle
Property
Assuming you are dealing with the standard TreeView control, you can do this in the TreeDataBound Event.
A brief example (not tested):
<asp:TreeView runat="server"
ID="tvMyTreeView"
OnTreeNodeDataBound="tvMyTreeView_TreeNodeDataBound"
/>
And the backend:
protected void tvMyTreeView_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
DataRowView dr = (DataRowView)e.Node.DataItem;
e.Node.Style.Add("color", dr["COLOR"].ToString());
}
If you are using the Telerik RadTreeView, then the event name is NodeDataBound
You will probably have to tweak the example to better fit your needs, but hopefully this will get you started.
Related
Currently, I am using RadTreeView Telerik control for showing hierarchical data along withadd/edit/delete functionalities for each node. Using TreeView - Context Menu, that has been achieved, but I am trying to implement it as shown in below:
It works the following way:
a) When a node is expanded by clicking "+" icon, "Add Group" button is visible at the bottom of its last child.
b) When a node is selected, "Edit" and "Delete" icons appear.
On clicking any of those icons will open a Dialog for respective actions.
So, I need to replace Context Menu with the display shown in mock. I tried to use NodeTemplate something like below:
<NodeTemplate>
<div>
<span>Test</span>
</div>
</NodeTemplate>
but, it makes the text of all nodes as "Test".
Can somebody please help me out?
<script type="text/javascript">
function OnClientContextMenuItemClicking(sender, args)
{
var menuItem = args.get_menuItem();
var treeNode = args.get_node();
menuItem.get_menu().hide();
switch (menuItem.get_value())
{
case "edit":
treeNode.startEdit();
break;
}
}
</script>
Hope this helps,
I implemented the RadTreeView in serverside. I though it is easy to manage in server side, specially when it comes to binding and handling the events
This is my Default.aspx.cs
using Telerik.Web.UI;
public partial class Default : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
}
protected void RadTreeView1_NodeEdit(object sender, RadTreeNodeEditEventArgs e)
{
// This is the serverside event that is triggered on Edit
RadTreeNode nodeEdited = e.Node; // This is the current node that is clicked
string newText = e.Text;
nodeEdited.Text = newText;
}
//
//.........
//.........
}
This is something extra. In server-side you can also find a node like this,
RadTreeNode node = RadTreeView1.FindNodeByText("TestOne");
// now edit and change any test
node.Text = "Test";
I hope this helps.
I am trying to find all asp:Image controls in the vb.net code behind to dynamically set the ImageUrl to the same image file. This I can do seperately for each control, but writing 10+
imgQuestion.ImageUrl = cdn.Uri.ToString & "images/question.png" lines seems a little silly. I do not need to skip any image controls - every single one on the page will be changed. Is there any way to identify all of them without specifying each ID?
The IDs are not all named something similar, such as "Image1", "Image2" but rather "PaymentNote", "search", etc so I cannot loop through all the numbers with something like FindControl("Image" & controlNumber)
Is there another way to do this? I'd prefer to keep the image control IDs as something meaningful.
You can recursively use FindControl, starting from the Page and for each control check if it's an <asp:Image...
My own preferred language of choice is C#, so I won't be able to show a VB example. But here's a C# example:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ChangeImageUrls(Page);
}
private void ChangeImageUrls(Control ctrl)
{
foreach (Control subCtrl in ctrl.Controls)
{
if (subCtrl is Image)
{
((Image)subCtrl).ImageUrl = "...";
}
if (subCtrl.HasControls())
ChangeImageUrls(subCtrl);
}
}
}
I have a PlaceHolder control inside of a ListView that I am using to render controls from my code behind. The code below adds the controls:
TextBox tb = new TextBox();
tb.Text = quest.Value;
tb.ID = quest.ShortName.Replace(" ", "");
((PlaceHolder)e.Item.FindControl("ph_QuestionInput")).Controls.Add(tb);
I am using the following code to retrieve the values that have been entered into the TextBox:
foreach (ListViewDataItem di in lv_Questions.Items)
{
int QuestionId = Convert.ToInt32(((HiddenField)di.FindControl("hf_QuestionId")).Value);
Question quest = dc.Questions.Single(q => q.QuestionId == QuestionId);
TextBox tb = ((TextBox)di.FindControl(quest.ShortName.Replace(" ","")));
//tb is always null!
}
But it never finds the control. I've looked at the source code for the page and the control i want has the id:
ctl00_cphContentMiddle_lv_Questions_ctrl0_Numberofacres
For some reason when I look at the controls in the ListViewDataItem it has the ClientID:
ctl00_cphContentMiddle_lv_Questions_ctrl0_ctl00
Why would it be changing Numberofacres to ctl00? Is there any way to work around this?
UPDATE:
Just to clarify, I am databinding my ListView in the Page_Init event. I then create the controls in the ItemBound event for my ListView. But based on what #Womp and MSDN are saying the controls won't actually be created until after the Load event (which is after the Page_Init event) and therefore are not in ViewState? Does this sound correct?
If so am I just SOL when it comes to retrieving the values in my dynamic controls from my OnClick event?
UPDATE 2:
So i changed the code i had in my Page_Init event from:
protected void Page_Init(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
//databind lv_Questions
}
}
to:
protected void Page_Init(object sender, EventArgs e)
{
//databind lv_Questions
}
And it fixed my problem. Still a little confused as to why I want to databind regardless of whether it's a postback or not but the issue is resolved.
It looks like you're adding your textbox to a Placeholder control... but then you're searching a ListViewDataItem container for it later.
Seems to me that you need to search for the Placeholder first, and then search it for the textbox.
I have a page with a table of stuff and I need to allow the user to select rows to process. I've figured out how to add a column of check boxes to the table but I can't seem to figure out how to test if they are checked when the form is submitted. If they were static elements, I'd be able to just check do this.theCheckBox but they are programaticly generated.
Also I'm not very happy with how I'm attaching my data to them (by stuffing it in there ID property).
I'm not sure if it's relevant but I'm looking at a bit of a catch-22 as I need to known which of the checkboxes that were created last time around were checked before I can re-run the code that created them.
Edit:
I've found an almost solution. By setting the AutoPostBack property and the CheckedChanged event:
checkbox.AutoPostBack = false;
checkbox.CheckedChanged += new EventHandler(checkbox_CheckedChanged);
I can get code to be called on a post back for any check box that has changed. However this has two problems:
The call back is processed after (or during, I'm not sure) Page_Load where I need to use this information
The call back is not called for check boxes that were checked when the page loaded and still are.
Edit 2:
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.
I'm going to assume you're using a DataList but this should work with and Control that can be templated. I'm also going to assume you're using DataBinding.
Code Front:
<asp:DataList ID="List" OnItemDataBound="List_ItemDataBound" runat="server">
<ItemTemplate>
<asp:CheckBox ID="DeleteMe" runat="server"/>
<a href="<%# DataBinder.Eval(Container, "DataItem.Url")%>" target="_blank">
<%# DataBinder.Eval(Container, "DataItem.Title")%></a>
</ItemTemplate>
</asp:DataList>
<asp:Button ID="DeleteListItem" runat="server" OnClick="DeleteListItem_Click" ></asp:Button>
Code Behind:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadList();
}
protected void DeleteListItem_Click(object sender, EventArgs e)
{
foreach (DataListItem li in List.Items)
{
CheckBox delMe = (CheckBox)li.FindControl("DeleteMe");
if (delMe != null && delMe.Checked)
//Do Something
}
}
LoadList();
}
protected void LoadList()
{
DataTable dt = //Something...
List.DataSource = dt;
List.DataBind();
}
protected void List_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
string id = DataBinder.Eval(e.Item.DataItem, "ID").ToString();
CheckBox delMe = (CheckBox)e.Item.FindControl("DeleteMe");
if (delMe != null)
delMe.Attributes.Add("value", id);
}
}
}
First, make sure that each Checkbox has an ID and that it's got the 'runat="server"' in the tag.
then use the FindControl() function to find it.
For example, if you're looping through all rows in a GridView..
foreach(GridViewRow r in Gridview1.Rows)
{
object cb = r.FindControl("MyCheckBoxId");
if(r != null)
{
CheckBox chk = (CheckBox)cb;
bool IsChecked = chk.Checked;
}
}
Postback data is restored between the InitComplete event and the PreLoad event. If your checkboxes are not created until later then the checkboxes will play "catch up" with their events and the data will be loaded into the control shortly after it is created.
If this is to late for you then you will have to do something like what you are already doing. That is you will have to access the post data before it is given to the control.
If you can save the UniqueId of each CheckBox that you create then can directly access the post data without having to given them a special prefix. You could do this by creating a list of strings which you save the ids in as you generate them and then saving them in the view state. Of course that requires the view state to be enabled and takes up more space in the viewstate.
foreach (string uniqueId in UniqueIds)
{
bool data = Convert.ToBoolean(Request.Form[uniqueId]);
//...
}
Your post is a little vague. It would help to see how you're adding controls to the table. Is it an ASP:Table or a regular HTML table (presumably with a runat="server" attribute since you've successfully added items to it)?
If you intend to let the user make a bunch of selections, then hit a "Submit" button, whereupon you'll process each row based on which row is checked, then you should not be handling the CheckChanged event. Otherwise, as you've noticed, you'll be causing a postback each time and it won't process any of the other checkboxes. So when you create the CheckBox do not set the eventhandler so it doesn't cause a postback.
In your submit button's eventhandler you would loop through each table row, cell, then determine whether the cell's children control contained a checkbox.
I would suggest not using a table. From what you're describing perhaps a GridView or DataList is a better option.
EDIT: here's a simple example to demonstrate. You should be able to get this working in a new project to test out.
Markup
<form id="form1" runat="server">
<div>
<table id="tbl" runat="server"></table>
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</div>
</form>
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
var row = new HtmlTableRow();
var cell = new HtmlTableCell();
cell.InnerText = "Row: " + i.ToString();
row.Cells.Add(cell);
cell = new HtmlTableCell();
CheckBox chk = new CheckBox() { ID = "chk" + i.ToString() };
cell.Controls.Add(chk);
row.Cells.Add(cell);
tbl.Rows.Add(row);
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
foreach (HtmlTableRow row in tbl.Rows)
{
foreach (HtmlTableCell cell in row.Cells)
{
foreach (Control c in cell.Controls)
{
if (c is CheckBox)
{
// do your processing here
CheckBox chk = c as CheckBox;
if (chk.Checked)
{
Response.Write(chk.ID + " was checked <br />");
}
}
}
}
}
}
What about using the CheckBoxList control? I have no Visual Studio open now, but as far as I remember it is a DataBound control, providing DataSource and DataBind() where you can provide a list at runtime. When the page does a postback you can traverse the list by calling something like myCheckBoxList.Items and check whether the current item is selected by calling ListItem.Selected method. This should work.
Add them in an override of the CreateChildControls method of the Page. Be sure to give them an ID! This way they get added to the control tree at the correct time.
IMHO The best way would be to use DataBound Templated Control though, i.e. something like a ListView (in .NET 3.5). then in pageload after postback traverse all items in the databound control and use item.FindControl to get at the actual checkbox.
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.
This is partly in reference to this:
Why isn't the SelectedIndexChanged event firing from a dropdownlist in a GridView?
I thought it different enough to ask another question.
My thought is that instead of adding a dropdownlist (ddl) to a gridview and then using the technique above that I could create a brand new control that has a ddl in it and the reference it directly.
This is more of a how do I create asp.net 2.0+ controls, I think, but is what I am asking possible? Can you make a "new" gridview control that just happens to always have a ddl in it and just refer to it (somehow) without findcontrol and all the rest?
I realize it would be highly customized for a unique app. I am just trying to see if it is possible as I may want to use this to create other controls.
Thank you.
It depends on your definition of a "new GridView". The answer is yet, but at a cost.
If you base your control on WebControl, you can write a new grid control with any functionality. Somehow, I don't think this is what you have in mind.
If you want to inherit from the existing GridView and add extra controls, then it is also doable, but with heavy limitations. The reason is because GridView's implementation breaks every possible guideline for extensibility. I guess because they never meant it to be extended. For instance, they clear Controls collection almost on every occasion and explicitly expect for the Controls[0] to be a Table. I suppose, if you decide to stay within confines of the table layout (header, footer and all), then you may have more room to play.
Finally, you could create a wrapper, which has a GridView as its private member and simply expose everything you may need plus more. But that gets ugly very quickly.
Here is a crude demonstration (working) of the second approach. Note that the drop down is at the end. You can override the Render method, but you'd have to recreate a lot of MS code.
ExtendedGridView
public class ExtendedGridView : GridView
{
protected DropDownList DropDown { get; set; }
public ExtendedGridView() : base()
{
this.DropDown = new DropDownList();
this.DropDown.Items.Add("white");
this.DropDown.Items.Add("red");
this.DropDown.Items.Add("blue");
this.DropDown.Items.Add("green");
this.DropDown.AutoPostBack = true;
this.DropDown.ID = "dropdown";
this.DropDown.SelectedIndexChanged += new EventHandler(DropDown_SelectedIndexChanged);
}
void DropDown_SelectedIndexChanged(object sender, EventArgs e)
{
BackColor = System.Drawing.Color.FromName(this.DropDown.SelectedValue);
}
protected override int CreateChildControls(System.Collections.IEnumerable dataSource, bool dataBinding)
{
int itemCount = base.CreateChildControls(dataSource, dataBinding);
Controls.Add(this.DropDown);
return itemCount;
}
}
SomePage.aspx
<%# Register TagPrefix="my" Namespace="MyProject" Assembly="MyProject" %>
<my:ExtendedGridView id="myGridView" runat="server" onpageindexchanging="myGridView_PageIndexChanging"></my:ExtendedGridView>
SomePage.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
myGridView.DataSource = new string[] { "aaa", "bbb", "ccc", "ddd", "eee" };
myGridView.AllowPaging = true;
myGridView.PageSize = 2;
myGridView.DataBind();
}
protected void myGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
myGridView.PageIndex = e.NewPageIndex;
myGridView.DataBind();
}