I have a ListView with an EditItemTemplate that calls a method onItemEditing.
Within my ListView I have a CheckBoxList bound using LINQ.
In my onItemEditing method, I'm trying to check certain CheckBoxes if they are present in a look up table that links users with sectors.
However, when I load the EditItemTemplate none of the CheckBoxes are checked even though I've set them as selected in the onItemEditing method.
Here's the Method:
protected void onItemEditing(object sender, ListViewEditEventArgs e)
{
ListView1.EditIndex = e.NewEditIndex;
ListView1.DataBind();
int regId = Convert.ToInt32(((Label)ListView1.Items[e.NewEditIndex].FindControl("LblRegId")).Text);
CheckBoxList cbl = (CheckBoxList) ListView1.Items[e.NewEditIndex].FindControl("chkLstSectors");
//test to see if forcing first check box to be selected works - doesn't work
cbl.Items[0].Selected = true;
SqlConnection objConn = new SqlConnection(ConfigurationManager.ConnectionStrings["DaresburyConnectionString"].ToString());
SqlCommand objCmd = new SqlCommand("select * from register_sectors where register_id= " + regId, objConn);
objConn.Open();
SqlDataReader objReader = objCmd.ExecuteReader();
if (objReader != null)
{
while (objReader.Read())
{
ListItem currentCheckBox = cbl.Items.FindByValue(objReader["sector_id"].ToString());
if (currentCheckBox != null)
{
currentCheckBox.Selected = true;
}
}
}
}
Any ideas how to get around this?
The problem was the listView was being bound again after the checkboxlist was bound.
I removed the binding and it works!
I hope I'm not too late with my answer ;)
I have a CheckBoxList in a ListView which should DataBind like the other controls. The value in the database is a calculated value from this enumeration:
public enum SiteType
{
Owner = 1,
Reseller = 2,
SubReseller = 4,
Distributor = 8
Manufacturer = 16,
Consumer = 32
}
If the value is 24 this means Distributor and Manufacturer (8 + 16).
I added a HiddenField to the EditItem in my ListView for databinding the value:
<EditItemTemplate>
<tr>
<td>
<asp:CheckBoxList ID="cblSiteTypes" runat="server" RepeatLayout="Flow"
DataSourceID="ObjectDataSource4" DataTextField="Key" DataValueField="Value" />
<asp:HiddenField ID="hfSiteTypes" runat="server" Value='<%# Bind("SiteType") %>' OnDataBinding="hfSiteTypesBnd" />
</td>
</tr>
<!-- other data... -->
</EditItemTemplate>
The CheckBoxList is filled through another DataSource, which returns a Dictionary object with the data from the enumeration. In code behind I use the OnDataBinding method of the HiddenField for the selection:
protected void hfSiteTypesBnd( object sender, EventArgs e )
{
// read the value
HiddenField hf = (HiddenField)sender;
short val = Convert.ToInt16( hf.Value );
// find the checkboxlist
CheckBoxList cblSiteTypes = (CheckBoxList)hf.Parent.FindControl( "cblSiteTypes" );
// clear the selection (may be not needed)
cblSiteTypes.ClearSelection();
// for each item
foreach ( ListItem li in cblSiteTypes.Items )
{
// get the value from each item and...
short v = Convert.ToInt16( li.Value );
// ...look up whether this value is matching or not
if ( ( val & v ) == v ) li.Selected = true;
}
}
Et voilĂ !
Related
I want to program the checkboxes so that if a row is selected, the program will read the value in the first column of the gridview row and automatically check all rows that also have that value in their first column. I was able to do this using an array to store the value and running through each row, checking if this value was a match. If it matched, the checkbox was checked. This worked but was a very limited solution. When I tried to reverse the action, it simply rechecked that value automatically because that value was still in the array and I did not know how to distinguish between a check or un-check action. It was solely based on a change event.
int count = 0;
foreach (GridViewRow gvrow in GridView1.Rows)
{
CheckBox chk = (CheckBox)gvrow.FindControl("chkRow");
if (chk.Checked)
{
count++;
}
}
string [] dnum = new string[count];
int counter = 0;
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox myCheckBox = row.FindControl("chkRow") as CheckBox;
if (myCheckBox.Checked)
{
if (counter > 0)
{
int number = counter - 1;
if (row.Cells[1].Text != dnum[number])
{
dnum[counter] = row.Cells[1].Text;
counter++;
}
}
else
{
dnum[counter] = row.Cells[1].Text;
counter++;
}
}
}
return dnum;
}
The array dnum should return the first column values for the checked rows . With this I can run through each row and check if any checkboxes need to be checked.
foreach (GridViewRow gvrow in GridView1.Rows)
{
CheckBox ChkBox = (CheckBox)gvrow.FindControl("chkRow");
if (ChkBox.Checked == true)
{
foreach (string s in first)
{
if (gvrow.Cells[1].Text == s)
{
ChkBox.Checked = true;
}
}
}
But now I am unable to figure out how to reverse the process, i.e when I uncheck one, all with the same first column value must uncheck, instead it just rechecks because that value is still in the array. I am open to completely different methods.
Many thanks,
Nicolas
I don't clearly understand your problem, Maybe you're looking for this?
use this code instead of your old one in check ChkBox loop.
if (gvrow.Cells[1].Text == s)
{
ChkBox.Checked = !ChkBox.Checked;
}
With ChkBox.Checked = !ChkBox.Checked, It'll reverse value in checkbox.
If it was true, It'll become false. If it was false, It'll become true.
Will just give another example, not sure on how you are implementing at your code so here it goes...
For example you have your gridview as below:
<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="CheckBox1"
OnCheckedChanged="CheckBox1_Click"
AutoPostBack="True" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And in your code behind..
mockData data below is just sample data for our gridview to demonstrate the check and un-check of same value based on selected checkbox property and column[1] value.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var mockData = new[] {"1", "1", "2", "1", "3", "2"};
GridView1.DataSource = mockData;
GridView1.DataBind();
}
}
protected void CheckBox1_Click(object sender, EventArgs e)
{
var chkBox = (CheckBox) sender;
var selectedRow = chkBox.Parent.Parent;
var itemValue = ((GridViewRow)selectedRow).Cells[1].Text;
foreach (var chkItem in GridView1.Rows.Cast<GridViewRow>()
.Where(item => item.Cells[1].Text == itemValue)
.Select(item => item.Cells[0].FindControl("CheckBox1")).OfType<CheckBox>())
{
chkItem.Checked = chkBox.Checked;
}
}
}
If I click on checkbox in one row with value of "1", All rows with value of "1" should be automatically set to the property of selected checkbox.
Let me know if I misunderstood your requirement. You can apply to your code and let me know if it works :-) cheers.
I'm populating a dataGridview in my winforms application using a list of strings (single unnamed column), however I need a way to select a single sell by it's value in order to change the text color.
How can I do this?
this is how I'm populating it:
List<String> companyNames = new List<String>();
//.. other logic that fills up companyNames
companyDataGridView.DataSource = this.companyNames.Select(x => new { Value = x }).ToList();
After which I need to somehow select the cell, based on the value it gets from the list.
You can use an eval in the html, this means that you can call the server side function in each row and determine its colour.
Luckily I have already used this recently and here is an example:
<asp:TemplateField HeaderText="Level Achieved">
<ItemTemplate>
<asp:Label ID="lblActual" runat="server" Text='<%# Bind("Actual") %>' BackColor='<%# GetLevelColour(Eval("Target"),Eval("Actual"))%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlAchievedLevel" runat="server">
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
Here you can see that the backcolour of the cell is determined by what is returned from the function GetLevelColour, I also pass in two parameters that are used in the function.
This may or may not be the sort of function you require, however my interpretation of the question was how to change colour of a cell when its value is equal to a predetermined value (in this case a word of length 2 as the length was output to the cell instead of the string).
I dont know much about Winforms, however I gave it a shot. Whilst I couldn't get the list to bind strings, I could pull the value out and compare against a known value. Is this the sort of thing you are looking for?
private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value.ToString() == "2")
{
//To colour the row
row.DefaultCellStyle.BackColor = Color.Red;
//To select the row
row.Selected = true;
}
}
}
This might not be pretty, but I ended up throwing this together.. and it seems to work.
private DataGridViewCell GetDataGridViewCellByValue(String value, DataGridView dataGridView)
{
List<DataGridViewCell> myCells = new List<DataGridViewCell>();
foreach (DataGridViewRow myRow in dataGridView.Rows)
{
foreach (DataGridViewCell myCell in myRow.Cells)
{
myCells.Add(myCell);
}
}
DataGridViewCell returnCell = myCells.FirstOrDefault(x => x.Value.ToString() == value);
if (returnCell != null)
{
return returnCell;
}
return null;
}
Then simply using this below I can get the desired cell:
DataGridViewCell testCell = this.GetDataGridViewCellByValue("Company1", this.companyDataGridView);
if (testCell != null)
{
testCell.Style.ForeColor = Color.Blue;
}
This could be a scalable and fast solution :
Dictionary<string, Color> valuesForColors = new Dictionary<string, Color>();
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.FormattedValue != null && valuesForColors.ContainsKey(e.FormattedValue.ToString()))
e.CellStyle.ForeColor = e.CellStyle.SelectionForeColor = valuesForColors[e.FormattedValue.ToString()];
}
and I am having a function to convert this list to a datatable
public static DataTable ConvertToDatatable<T>(IList<T> data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
what should I do to bind these multiple values to a repeater or a gridview
You can take repeater or gridview inside parent gridview or repeater.
for example:-
Dictionary<int, object> g = new Dictionary<int, object>() { { 1, new { j = "g" } }, { 2, new { j = "ggfdf" } }, { 3, new { j = "gioret" } } };
gridviewparent.DataSource= g.Select(h => new {key= h.Key});
gridviewparent.DataBind();
foreach (GridViewRow item in gridviewparent.Rows)
{
int key= Convert.Toint32( ((Label)item.FindControl("lblkey")).Text) ;
GridView gridviewChild=(GridView)item.FindControl("gridviewchild");
// return g[key] in list
gridviewChild.DataSource= g[key];
gridviewChild.DataBind();
}
You could use a repeater inside a repeater. Here's how:
Convert your List into a Dictionary<string, List<object>> and store it into a Property (in my sample it is named Dict) that can be accessed by the .aspx file (at least protected or more accessible).
Then call outerRepeater.DataBind() at some point (For example in your Page_Load(object sender, EventArgs e) implementation).
Put this into your .aspx file to make it work:
<asp:Repeater runat="server" ID="outerRepeater" DataSource='<%# Dict.Keys%>'>
<ItemTemplate>
<asp:Repeater runat="server" ID="innerRepeater" DataSource='<%# Dict[DataBinder.Eval(Container, "DataItem").ToString()]%>'>
<ItemTemplate>
<%# DataBinder.Eval(Container, "DataItem")%>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
You can use <%# DataBinder.Eval(Container, "DataItem.EventDate")%> to access a Property (in this sample with the name EventDate) when you store concrete objects in the List inside the dictionary.
For example: Dictionary<string, List<Event>>
I think the only thing you have to do here ,so as to bind the dynamic datatable to a gridView, is to use the build-in property of asp Gridview control AutoGenerateColumns = "true"; unless you know exactly the columns you are up to bind so then you have to use a GridView.RowDataBound Event.
What is exactly this AutoGenerateColumns property ?
~ ASP CODE
<asp:GridView ID="MyGridView" runat="server" AutoGenerateColumns = "true" ></asp:GridView>
Suppose that myDatatable is the datatable object returned from your ConvertToDatatable method.
~ C# Code:
MyGridview.DataSource = myDatatable;
MyGridview.DataBind();
Hope it helps!
Im trying to bind my drop down list, i think is beacuse my asp code on the front end is not bound somehow
aspx
<asp:Label ID="Label2" runat="server" />
<asp:DropDownList Width="150px" ID="ddLocation" runat="server"
AppendDataBoundItems="True"
DataTextField="Name"
DataValueField="Name" AutoPostBack="True" >
</asp:DropDownList>
c# code
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Label0.Text = "Specialities";
Label1.Text = "Category";
Label2.Text = "Locations";
ddSpec.Items.Insert(0, new ListItem("Select a spec", "0"));
ddCategory.Items.Insert(0, new ListItem("Select a Category", "0"));
ddLocation.Items.Insert(0, new ListItem("<Select a Location>", "0"));
populattePage();
}
}
public void populattePage()
{
getlocation();
// getCategory()
}
public static void getlocation()
{
DataClasses_DataContext dc = new DataClasses_DataContext();
List<string> locations = (
from a
in dc.Locations
select a.Name).ToList();
DropDownList ddLocation = new DropDownList();
ddLocation.DataSource = locations;
ddLocation.DataValueField = "ID";
ddLocation.DataTextField = "Name";
ddLocation.SelectedIndex = 0;
ddLocation.DataBind();
}
I now have the Error """"DataBinding: 'System.String' does not contain a property with the name 'Name'.""" the code in the """page load""" class adds items to the drop downs however when i call the get locations class I get this error, Please help thanks in advance
There are two issues here. First - if you are going to use 2 properties of the Location object, you should use this object as a data source. No point to extract separate list of strings for this:
ddLocation.DataSource = dc.Locations.ToList();
This will resolve your exception. Also this line:
DropDownList ddLocation = new DropDownList();
should not be here, just remove it. You already have your drop down initialized.
Second issue - if you want some default item to appear in the list, you should insert it after the data binding:
populattePage();
ddLocation.Items.Insert(0, new ListItem("<Select a Location>", "0"));
ListItems have the properties "Text" and "Value". So when you create one, you can only use those properties for the drop down list text/value fields. You need to change
<asp:DropDownList Width="150px" ID="ddLocation" runat="server"
AppendDataBoundItems="True"
DataTextField="Text"
DataValueField="Value" AutoPostBack="True" >
</asp:DropDownList>
A simple way to get your location would be
List<ListItem> locations = (from a in dc.Locations
select new ListItem()
{
Text = a.Name,
Value = a.Name
}).ToList();
Then append that to your list.
So the problem is the data source you're binding to is primarily string. When you set the DataValueField and DataTextField properties, it calls the reflector and asks the object its being bound to, to give it the property. Since I'm assuming the a.Name in the query is a string, it would not have a "Name" or "Id" property. A simple solution to this would be to create an ID and Name property.
This might help illustrate what I'm trying to say. (also please camel-case your function names if you plan to do C# it helps us maintenance programmers :))
public static void GetLocation()
{
DataClasses_DataContext dc = new DataClasses_DataContext();
var locations = (
from a
in dc.Locations
select new { Name = a.Name, Id = a.Id }).ToList(); // this can be Id = a.Name or whatever too
DropDownList ddLocation = new DropDownList();
ddLocation.DataSource = locations;
ddLocation.DataValueField = "ID";
ddLocation.DataTextField = "Name";
ddLocation.SelectedIndex = 0;
ddLocation.DataBind();
}
Hope that helps!
I'm having a problem with CheckBoxList and OnSelectedIndexChanged:
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:CheckBoxList
id="lstWatchEType"
runat="server"
DataTextField="DescriptionText"
DataValueField="Id"
AutoPostBack="true"
OnSelectedIndexChanged="lstWatchEType_SelectedIndexChanged"/>
</ContentTemplate>
</asp:UpdatePanel>
This is populated in Page_Load (!IsPostBack)
public static void PopulateWatchEType(CheckBoxList list, Guid clientId)
{
OffertaDataContext db = new OffertaDataContext();
var ds = (from e in db.EnquiryTypes select new {
Id = e.Id,
DescriptionText = e.DescriptionText,
IsWatching = !db.WatchXrefEnquiryTypes.Any(f => f.ClientId.Equals(clientId) && f.EnquiryTypeId==e.Id && f.Inbox==false)
});
list.DataSource = ds;
list.DataBind();
foreach(var item in ds)
{
list.Items.FindByValue(item.Id.ToString()).Selected = item.IsWatching;
}
}
My problem is in:
protected void lstWatchEType_SelectedIndexChanged(Object sender, EventArgs e)
{
ListItem item = lstWatchEType.SelectedItem;
...
}
Where item is always the first element in the list???
The selected item property will return the selected item with the lowest index inside of the list. If the first item is selected, then it will return the first item.
To get the latest selected item, perhaps you can create a global variable and set that variable on index changed. You can create a ListItem collection that first holds all of the initial selected indexes like Kirtan suggested, then create a new collection that holds all of the newest selections whenever the selected index changes. Match the two lists, and whatever item is in the new list that is not in the older list is your latest selected index.
Hope this helps.