Using ASPxComboBox with ASPxGridView, need to set initial value - asp.net

I'm trying to use ASPxGridView to display a list of ASPxComboBox controls. Both the rows in the grid and the list of options in the combo boxes are populated from code. I'm having problems setting the initial value of the combo boxes.
I'm looking for it to look similar to the image below.
As you can see in the screenshot, I have been able to get both the grid view & the combo boxes to populate, but I can't figure out how to set the initial values of the combo boxes.
In the Init event of the inner combo boxes, there's no obvious property to retrieve the bound object.
I did find a couple other questions on StackOverflow, for which the answer was to add a bound property to the combo box. However, adding SelectedIndex='<%# Bind("Level") %>' to the declaration for InnerCombo gave me the error "Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control."
Here's what I have so far:
Testing.aspx:
<%# Page Title="" Language="C#" MasterPageFile="~/Light.master"
AutoEventWireup="true" CodeBehind="Testing.aspx.cs" Inherits="MyProject.Testing" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<dx:ASPxGridView ID="MyGridView" runat="server" KeyFieldName="Name">
<Columns>
<dx:GridViewDataColumn FieldName="Name" />
<dx:GridViewDataColumn FieldName="Level">
<DataItemTemplate>
<dx:ASPxComboBox
runat="server"
ID="InnerCombo"
ValueField="ID"
TextField="Desc"
ValueType="System.Int32"
OnInit="InnerCombo_Init" />
</DataItemTemplate>
</dx:GridViewDataColumn>
</Columns>
</dx:ASPxGridView>
<dx:ASPxButton runat="server" ID="btnSubmit" Text="Submit" OnClick="btnSubmit_Click" />
</asp:Content>
Testing.aspx.cs:
public partial class Testing : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.MyGridView.DataSource = GetDefaultSettings();
this.MyGridView.DataBind();
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
Debug.WriteLine("btnSubmit_Click");
for (int i = 0; i < MyGridView.VisibleRowCount; i++)
{
object[] row = (object[])MyGridView.GetRowValues(i, "Name", "Value");
// row[1] is null, but we can get the data by finding the combo box itself.
GridViewDataColumn col = (GridViewDataColumn)MyGridView.Columns["Value"];
ASPxComboBox innerCombo = (ASPxComboBox)MyGridView.FindRowCellTemplateControl(i, col, "InnerCombo");
Debug.WriteLine("{0} = {1}", row[0], innerCombo.Value);
}
}
protected void InnerCombo_Init(object sender, EventArgs e)
{
Debug.WriteLine("InnerCombo_Init");
ASPxComboBox innerCombo = sender as ASPxComboBox;
if (innerCombo != null)
{
innerCombo.DataSource = GetValues();
innerCombo.DataBind();
}
}
private static List<ValueClass> GetValues()
{
// Simple for testing; actual method will be database access.
return new List<ValueClass>()
{
new ValueClass(0, "Zero (default)"),
new ValueClass(1, "One"),
new ValueClass(2, "Two"),
new ValueClass(3, "Three"),
};
}
private static List<SettingClass> GetDefaultSettings()
{
// Simple for testing; actual method will be database access + post-processing.
return new List<SettingClass>()
{
new SettingClass("AA", 0),
new SettingClass("BB", 1),
new SettingClass("CC", 0),
};
}
public class ValueClass
{
public int ID { get; private set; }
public string Desc { get; private set; }
public ValueClass(int id, string desc)
{
this.ID = id;
this.Desc = desc;
}
}
public class SettingClass
{
public string Name { get; set; }
public int Value { get; set; }
public SettingClass(string name, int value)
{
this.Name = name;
this.Value = value;
}
}
}

Related

Properties of WebUserControl are null in DataBind override

I have WebUserControl with DataBind override:
public partial class WebUserControl1 : System.Web.UI.UserControl
{
public object DataSource { get; set; }
public string Text { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
}
public override void DataBind()
{
// *** there when called, properties are null, why? ***
repeater2.DataSource = DataSource;
repeater2.DataBind();
}
}
This control is in repeater with declarative bounded properties:
<asp:Repeater ID="repeater" runat="server">
<ItemTemplate>
<WebUserControl1 runat="server" DataSource='<%# DataBinder.Eval(Container.DataItem, "levels") %>' Text='<%# DataBinder.Eval(Container.DataItem, "Text") %>' />
</ItemTemplate>
</asp:Repeater>
Now when i call DataBind() on repeater:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
... data query
repeater.DataSource = items;
repeater.DataBind();
}
}
in overriden control's DataBind() method i don't have properly setted properties DataSource and Text, they are null, why?
If you have only one repeater control in WebUserControl1, it is easier to bind that child repeater control in Repeater.ItemDataBound Event of Parent repeater.
Here is the sample -
ASPX
<asp:Repeater ID="ParentRepeater" runat="server" OnItemDataBound="ParentRepeater_ItemDataBound">
<ItemTemplate>
<asp:Label runat="server" ID="StreetLabel" /><br/>
<asp:Repeater ID="ChildRepeater" runat="server">
<ItemTemplate>
<asp:Label runat="server" ID="FirstNameLabel" />
<asp:Label runat="server" ID="LastNameLabel" />
</ItemTemplate>
</asp:Repeater><hr/>
</ItemTemplate>
</asp:Repeater>
Code Behind
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public List<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ParentRepeater.DataSource = new List<Address>
{
new Address
{
Id = 1,
Street = "1st Street",
Users = new List<User>()
{
new User {Id = 1, FirstName = "John", LastName = "Doe"},
new User {Id = 1, FirstName = "Marry", LastName = "Doe"}
}
},
new Address
{
Id = 2,
Street = "2nd Street",
Users = new List<User>()
{
new User {Id = 1, FirstName = "Eric", LastName = "Newton"},
new User {Id = 1, FirstName = "John", LastName = "Newton"}
}
}
};
ParentRepeater.DataBind();
}
}
protected void ParentRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var address = e.Item.DataItem as Address;
var streetLabel = e.Item.FindControl("StreetLabel") as Label;
streetLabel.Text = address.Street;
var repeater = e.Item.FindControl("ChildRepeater") as Repeater;
repeater.ItemDataBound += ChildRepeater_ItemDataBound;
repeater.DataSource = address.Users;
repeater.DataBind();
}
}
protected void ChildRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
var user = e.Item.DataItem as User;
var firstNameLabel = e.Item.FindControl("FirstNameLabel") as Label;
firstNameLabel.Text = user.FirstName;
var lastNameLabel = e.Item.FindControl("LastNameLabel") as Label;
lastNameLabel.Text = user.LastName;
}
}
Solution for Original Question
Delete public override void DataBind() event and bind repeaters2 inside PreRender event.
public partial class WebUserControl1 : System.Web.UI.UserControl
{
protected override void OnPreRender(EventArgs e)
{
repeater2.DataSource = DataSource;
repeater2.DataBind();
base.OnPreRender(e);
}
}

Custom user control data source

I have a custom control that has a DropDownList inside and it's created by CreateUserControl. I'm saving data source directly to dropdown control. After page postbacked my binded data disappear. Should i save/restore my binded data myself in some tricky way?
public class EnumDropDownList : UserControl
{
private readonly DropDownList _ddlSelector;
private Dictionary<long, string> _dataSource;
public EnumDropDownList()
{
_ddlSelector = new DropDownList();
_dataSource = new Dictionary<long, string>();
}
public object DataSource
{
set
{
// datasource logic
}
}
public long SelectedValue
{
get { return Convert.ToInt64(_ddlSelector.SelectedValue); }
set { _ddlSelector.SelectedValue = value.ToString(); }
}
public override void DataBind()
{
_ddlSelector.DataSource = _dataSource;
_ddlSelector.DataTextField = "Value";
_ddlSelector.DataValueField = "Key";
_ddlSelector.DataBind();
base.DataBind();
}
[PermissionSet(SecurityAction.Demand, Name = "Execution")]
protected override void CreateChildControls()
{
Controls.Add(_ddlSelector);
}
}
You code is combination of UserControl and CustomServerControl.
It could have be a lot easier if you implement one instead of combination.
I created two controls - UserControl and CustomServerControl.
UserControl
Place the dropdownlist to ASPX instead of loading dymaiclally. If you load dynamically, you'll have to take care of persistence of control.
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="EnumDropDownList.ascx.cs"
Inherits="WebApplication2010.EnumDropDownList" %>
<asp:DropDownList runat="server" ID="DropDownList1" />
public partial class EnumDropDownList : System.Web.UI.UserControl
{
private Dictionary<long, string> _dataSource;
public EnumDropDownList()
{
_dataSource = new Dictionary<long, string>();
}
public Dictionary<long, string> DataSource
{
set { _dataSource = value; }
}
public long SelectedValue
{
get { return Convert.ToInt64(DropDownList1.SelectedValue); }
set { DropDownList1.SelectedValue = value.ToString(); }
}
public override void DataBind()
{
DropDownList1.DataSource = _dataSource;
DropDownList1.DataTextField = "Value";
DropDownList1.DataValueField = "Key";
DropDownList1.DataBind();
base.DataBind();
}
}
Custom Server Control (it is a lot easier to implement for your case)
It basically inherits DropDownList web control.
public class MyDropDownList : DropDownList
{
public long SelectedInt64Value
{
get { return Convert.ToInt64(SelectedValue); }
set { SelectedValue = value.ToString(); }
}
public Dictionary<long, string> DataSource
{
get { return (Dictionary<long, string>)ViewState["DataSource"]; }
set { ViewState["DataSource"] = value; }
}
public override void DataBind()
{
foreach (var item in DataSource)
Items.Add(new ListItem(item.Value, item.Key.ToString()));
base.DataBind();
}
}
Usage
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm5.aspx.cs" Inherits="WebApplication2010.WebForm5" %>
<%# Register Src="EnumDropDownList.ascx" TagName="EnumDropDownList" TagPrefix="uc1" %>
<%# Register TagPrefix="asp" Namespace="WebApplication2010" Assembly="WebApplication2010" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<uc1:EnumDropDownList ID="EnumDropDownList1" runat="server" />
<asp:Button runat="server" ID="Button1" Text="Submit" OnClick="Button1_Click" />
<asp:MyDropDownList id="MyDropDownList1" runat="server" />
</form>
</body>
</html>
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
Dictionary<long, string> dataSource = new Dictionary<long, string>();
dataSource.Add(1, "One");
dataSource.Add(2, "Two");
EnumDropDownList1.DataSource = dataSource;
EnumDropDownList1.DataBind();
MyDropDownList1.DataSource = dataSource;
MyDropDownList1.DataBind();
}
}
In some cases I have saved the dataset in a session variable. Whicn can then be referenced after postbacks. Something like this:
Session.Add("dataSource", _dataSource);//create the session variable
Then you can reference it, depending on the type the data source is (in example I used a datable)
_ddlSelector.DataSource = (DataTable)Session["dataSource"];
THis Is aspx file :
<telerik:RadComboBox ID="cmbCurrency" runat="server" Width="200px" MaxHeight="200px"
EmptyMessage="Select a currency" AutoPostBack="true" Filter="Contains" EnableLoadOnDemand="true">
</telerik:RadComboBox>
This is code Behind :
if (!IsPostBack)
{
popCurrencyName();
}
public void popCurrencyName()
{
DataTable dtCurrency = objCurrencyBAL.getCurrency(long.MinValue);
if (dtCurrency.Rows.Count > 0)
{
cmbCurrency.DataSource = dtCurrency;
cmbCurrency.DataTextField = "Name";
cmbCurrency.DataValueField = "CurrencyId";
cmbCurrency.DataBind();
}
}
Try this code:

Gridview using Boundfield onclick event

I'm using a gridview that I want to be able to click on each row to be able to display another field from the object that I'm displaying. It feels like it's easy to solve but maybe I'm stupid because I can't find it anywhere...
The ASP-code:
<asp:GridView ID="gvMessages" runat="server" AutoGenerateColumns = "false"
CaptionAlign="NotSet" CellPadding="5">
<Columns>
<asp:BoundField HeaderText="Avsändare" DataField="Sender" />
<asp:BoundField HeaderText="Ämne" DataField="Head" />
</Columns>
</asp:GridView>
Code-Behind:
protected void Page_Load(object sender, EventArgs e)
{
gvMessages.DataSource = con.GetMails(con.GetId(Membership.GetUser().UserName));
gvMessages.DataBind();
}
Not sure that all this is necessery for the problem but here is the method in my wcf-project that is filling my composite class with object info
public List<MailInfo> GetMails(int id)
{
using (var client = new datingEntities())
{
var result = client.Mail.Where(x => x.SentTo == id).Select(x => new MailInfo
{
Message = x.Mail1,
Reciever = x.SentTo,
Read = (bool)x.IsRead,
Sender = (int)x.SentFrom,
Head = x.Subject
}).ToList();
return result;
}
}
Composite-class:
[DataContract]
public class MailInfo : Mail
{
[DataMember]
public string Message { get; set; }
[DataMember]
public int Reciever { get; set; }
[DataMember]
public bool Read { get; set; }
[DataMember]
public int Sender { get; set; }
[DataMember]
public string Head { get; set; }
}
You should databind the GridView only if(!Page.IsPostBack).
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
gvMessages.DataSource = con.GetMails(con.GetId(Membership.GetUser().UserName));
gvMessages.DataBind();
}
}
If you want to select a row on click you can use javascript:
protected void gvMessages_RowCreated(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow) {
e.Row.Attributes["onmouseover"] = "this.style.cursor='pointer';this.style.textDecoration='underline';";
e.Row.Attributes["onmouseout"] = "this.style.textDecoration='none';";
e.Row.ToolTip = "Click to select row";
e.Row.Attributes["onclick"] = this.Page.ClientScript.GetPostBackClientHyperlink(this.GridView1, "Select$" + e.Row.RowIndex);
}
}
Now you can handle the SelectedIndexChangedEvent whenever the user clicks somewhere in the row:
protected void gvMessages_SelectedIndexChanged(Object sender, EventArgs e)
{
// Get the currently selected row using the SelectedRow property.
GridViewRow row = CustomersGridView.SelectedRow;
}
You should use the OnSelectedIndexChanged event.
<asp:GridView ID="gvMessages" runat="server" AutoGenerateColumns = "false"
OnSelectedIndexChanged="gvMessages_SelectedIndexChanged"
CaptionAlign="NotSet" CellPadding="5">
<Columns>
<asp:BoundField HeaderText="Avsändare" DataField="Sender" />
<asp:BoundField HeaderText="Ämne" DataField="Head" />
</Columns>
</asp:GridView>
Then in the event's definition, you can retrieve the selected item and do whatever you need from there.
protected void gvMessages_SelectedIndexChanged(object sender, EventArgs e)
{
if (ContactsGridView.SelectedIndex >= 0)
ViewState["SelectedKey"] = gvMessages.SelectedValue;
else
ViewState["SelectedKey"] = null;
}
Example from the MSDN official documentation.

ASP.NET DynamicData Validate Custom Image FieldTemplate

I've created a custom Image Field Template which works fine. I decided to create some kind of validation for image sizes so I've created a custom validation attribute. here is the code:
public class ImageSizeValidator : ValidationAttribute
{
public long MaxSize { get; set; }
public long MinSize { get; set; }
public override bool IsValid(object value)
{
if (value == null)
return true;
byte[] image = (byte[]) value;
if (image.Length / 1024L > MaxSize || image.Length / 1024L < MinSize)
return false;
return true;
}
}
and here is my FieldTemplate Image_Edit.ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Image_Edit.ascx.cs" Inherits="RastinArgham.CRM.Web.DynamicData.FieldTemplates.Image_Edit" %>
<asp:FileUpload ID="FileUpload1" runat="server" OnDataBinding="FileUpload1DataBinding" />
<asp:RequiredFieldValidator runat="server" ID="RequiredFieldValidator1" CssClass="DDControl DDValidator" ControlToValidate="FileUpload1" Display="Static" Enabled="false" />
<asp:DynamicValidator runat="server" ID="DynamicValidator1" CssClass="DDControl DDValidator" ControlToValidate="FileUpload1" Display="Static" />
and here is Image_Edit.ascx.cs:
public partial class Image_Edit : System.Web.DynamicData.FieldTemplateUserControl
{
protected void Page_Load(object sender, EventArgs e)
{
SetUpValidator(RequiredFieldValidator1);
SetUpValidator(DynamicValidator1);
}
protected override void ExtractValues(IOrderedDictionary dictionary)
{
if (FileUpload1.PostedFile == null || String.IsNullOrEmpty(FileUpload1.PostedFile.FileName) || FileUpload1.PostedFile.InputStream.Length == 0)
return;
dictionary[Column.Name] = FileUpload1.FileBytes;
}
public override Control DataControl
{
get
{
return FileUpload1;
}
}
}
and finally my entity meta data class:
[Display(Name = "ServicePhoto", Order = 410, GroupName = "Misc")]
[HideColumnIn(PageTemplate.List)]
[UIHint("Image")]
[ImageSizeValidator(ErrorMessage = "Invalid Photo Size", MinSize = 30, MaxSize = 300)]
public object ServicePhoto { get; set; }
There are two problems:
1- when IsValid(object value) called value is always null!
2- when trying to upload a new image I always get "The value is not valid" Error on client side of
validation.

Bind text box to value

How to bind to textbox and retrieve modified value on button click.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Sku objSku = new Sku();
objSku.Name = "Test";
Sku = objSku;
frm.DataSource = Sku;
frm.DataBind();
}
if (IsPostBack)
{
Sku = ViewState["Sku"] as Sku;
}
}
public Sku Sku { get; set; }
protected void Button1_Click(object sender, EventArgs e)
{
//Hers sku.Name should be equal to the value entered by the user . so that I can save the object.
}
}
[Serializable]
public class Sku
{
public string Name { get; set; }
}
Html code
<form id="form1" runat="server">
<div>
<asp:FormView runat="server" ID="frm" >
<ItemTemplate>
</ItemTemplate>
</asp:FormView>
<asp:TextBox ID="TextBox1" Text='<%# Bind("Name") %>' runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
</div>
</form>
You have direct access to your textbox as it's not in the FormView so:
String val= Textbox1.Text;
Textbox1.Text="what ever you are binding?"
I think you may need to be a little clear in your question as I don't understand what you are trying to do?
It looks like you're already binding to the field for displaying data. Is this not working? Within your button click event handler, you can retrieve the current value from TextBox1.Text.
If you want to update your view on postback you need to update the bindings.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Sku objSku = new Sku();
objSku.Name = "Test";
Sku = objSku;
}
if (IsPostBack)
{
Sku = ViewState["Sku"] as Sku;
}
frm.DataSource = Sku;
frm.DataBind();
}

Resources