I have a DropDownList control which really don't want to enable ViewState for as the item list is readily available from the server.
In this situation a post-back will obviously show an empty Items list, but at the same time I want the SelectedIndexChanged event to fire (using AutoPostBack)
The DropDownList control is actually dynamically created as part of a Composite Control which created an arbitrary number of DDLs - some of whose Items are sourced from the ASPX file (composite control contents) and others whose Items are bound to a data source. I am hoping that this complication isn't the source of the problem.
My thinking is that I should bind the list data to the Items collection on initial PageLoad and also rebind it late on PostBacks but I am not sure when. I am also not sure if the SelectedIndexChanged event handler will get called if on PostBack there is an empty Items list again.
Because it is part of a CompositeControl, I wonder if I should store some additional information in Control State. Would implementing something in the Conposite Control's Save/LoadControlState, Save/LoadViewState, RaisePostDataChangedEvent or RaisePostbackEvent be the solution?
Maybe I should rebind the Item list again early on PostBack e.g.before PageLoad?
Any pointers will be appreciated.
Thanks
Code provided below (cut out most of what is not relevant to problem)
Page ASPX
Note that I want to populate the ListItems of the { Group, Location, Division and BusinessUnit } DropDownLists dynamically with the items not being in dumped to ViewState but { Enabled } DDL is the static items defined below.
<cc1:FilterBar ID="FilterBar1" runat="server" CssClass="filterbar" OnFilterChanged="OnFilterChanged">
<cc1:Filter ID="Group" Label="Group" Type="DropDownList" />
<cc1:Filter ID="Location" Label="[Location]" Type="DropDownList" />
<cc1:Filter ID="Division" Label="[Division]" Type="DropDownList" />
<cc1:Filter ID="BusinessUnit" Label="[Business Unit]" Type="DropDownList" />
<cc1:Filter ID="Enabled" Label="Users" Type="DropDownList">
<asp:ListItem Value="X" Text="All"></asp:ListItem>
<asp:ListItem Value="1" Text="Active Only"></asp:ListItem>
<asp:ListItem Value="0" Text="Archived Only"></asp:ListItem>
</cc1:Filter>
</cc1:FilterBar>
Page Code Behind
protected void Page_Load(object sender, EventArgs e)
{
//if (!Page.IsPostBack) // whether to restire BindFilterBar() to first load or not?
BindFilterBar();
}
protected void BindFilterBar()
{
var h = new FilterBarBindHelper(FilterBar1);
h.AutoBindLocation(Filter.UserLocation.ID);
h.AutoBindDivision(Filter.UserDivision.ID);
h.AutoBindBusinessUnit(Filter.UserBusinessUnit.ID);
h.AutoBindGroup(Filter.UserGroup.ID);
var filter = FilterBar1.GetFilterByID("Enabled");
filter.SelectedValue = Filter.UserEnabledAsChar.ToString();
}
protected void OnFilterChanged(object sender, FilterChangedEventArgs e)
{
Debug.WriteLine($"[CompletionResults.aspx] OnFilterChanged(e={{FilterID={e.FilterID}; NewValue={e.NewValue} NewText={e.NewText}}})");
switch(e.FilterID)
{
case "Enabled":
Filter.UserEnabledAsChar = e.NewValue;
break;
case "Group":
if (e.NewValueAsInt == null)
Filter.UserGroup.Reset();
else
Filter.UserGroup.Set((int)e.NewValueAsInt, e.NewText);
break;
case "Division":
if (e.NewValueAsInt == null)
Filter.UserDivision.Reset();
else
Filter.UserDivision.Set((int)e.NewValueAsInt, e.NewText);
break;
case "BusinessUnit":
if (e.NewValueAsInt == null)
Filter.UserBusinessUnit.Reset();
else
Filter.UserBusinessUnit.Set((int)e.NewValueAsInt, e.NewText);
break;
case "Location":
if (e.NewValueAsInt == null)
Filter.UserLocation.Reset();
else
Filter.UserLocation.Set((int)e.NewValueAsInt, e.NewText);
break;
default:
return;
}
// Update Selection Text
BindSelectionText();
// Update the Grid
BindGrid();
}
/// <summary>
/// User has selected a new Page number from the UserGrid
/// </summary>
protected void OnPageChanged(object sender, EventArgs args)
{
Filter.ShowAllRows = false;
Filter.PageIndex = UserGrid.PageIndex;
BindGrid();
}
protected void OnAction(object sender, ToolbarActionClickedEventArgs args)
{
if (args.ActionValue == "email")
OnEmail();
}
FilterBarBindHelper.cs
public class FilterBarBindHelper
{
private readonly FilterBar _filterBar;
private readonly OrganisationProperties _orgProps;
public FilterBarBindHelper(FilterBar filterBar)
{
if (filterBar == null)
throw new ArgumentNullException(nameof(filterBar));
_filterBar = filterBar;
_orgProps = ObjectCache.GetOrganisationProperties();
}
/// <summary>
/// Binds Group list data to Filter, optionally creating the Filter if it doesn't exist
/// </summary>
/// <param name="selectedID">ID of currently selected Group to filter by (0 or null if none)</param>
/// <param name="createFilter">Create the Filter if not found</param>
public void AutoBindGroup(int? selectedID, bool createFilter = true)
{
// All Organisations have Groups.
// Only populate if a FilterBar Filter with ID="Groups" can be found or if createFilter = true
var f = _filterBar.GetFilterByID("Group");
if (f == null)
if (createFilter)
f = CreateFilter("Group", "Group");
else
return;
// Populate Filter list with items
var src = GroupCache.Get();
f.Items.Clear();
f.Items.Add(Any());
f.Items.AddRange(src.Select(s => new ListItem() { Value = s.StringID, Text = s.Name }).ToArray());
// Assign localised name
f.Label = _orgProps.GroupNm;
// Select
if((selectedID ?? 0) != 0)
f.SelectedValue = selectedID.Value.ToString();
_filterBar.RefreshFilter(f);
}
/// <summary>
/// Create a FilterBar Filter and add it to the FilterBar
/// </summary>
/// <param name="filterID">ID of filter to add</param>
/// <param name="label">Filter's label</param>
/// <param name="type">Filter's type</param>
/// <returns>New Filter</returns>
private Filter CreateFilter(string filterID, string label, FilterType type = FilterType.DropDownList)
{
var f = new Filter() { ID = filterID, Type = type, Label = label };
_filterBar.Filters.Add(f);
return f;
}
private ListItem Any()
{
return new ListItem("Any", "X");
}
}
Toolbar.cs
[
AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
DefaultProperty("Items"),
ParseChildren(true, "Items"),
ToolboxData("<{0}:Toolbar runat=server />"),
Designer(typeof(ToolbarDesigner))
]
public class Toolbar : CompositeControl
{
private string _preText = "Actions: ";
private bool _showRight = true;
private readonly List<ToolbarItem> _list = new List<ToolbarItem>();
public Toolbar()
{
PreText = "Actions: ";
ObjectNameSingle = "Item";
ObjectNamePlural = "Items";
ShowRight = true;
}
protected override HtmlTextWriterTag TagKey { get { return HtmlTextWriterTag.Div; } }
[
Category("Behavior"),
Description("The Item collection"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(ToolbarCollectionEditor), typeof(UITypeEditor)),
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public List<ToolbarItem> Items
{
get { return _list; }
}
//various properties (snip)
protected override void RenderContents(HtmlTextWriter writer)
{
if(_leftSide != null)
_leftSide.RenderControl(writer);
if(_rightSide != null)
_rightSide.RenderControl(writer);
if(_leftSide == null && _rightSide == null && DesignMode)
writer.Write("No Toolbar Items have been set up in designer");
}
public void RebuildChildControls()
{
// Indicate that the child controls need rebuilding
// Ref: http://yourdotnetdesignteam.blogspot.co.uk/2008/09/life-cycle-of-aspnet-controls_28.html "Composite Controls" section:
// "Note 1: When the Composite Control is displayed normally, 'CreateChildControls' is called AFTER the 'Load' method.
// However, when a post back event occurs, 'CreateChildControls' is called AFTER the 'Init' method.
// This certainly makes the 'CreateChildControls' method an "interesting" aspect of the Life Cycle."
// So on postback, the calling method should call RebuildChildControls() after repopulating/modifying Filter Items
ChildControlsCreated = false;
//RecreateChildControls(); this will happen in due course anyway
}
// Controls in Composite Control
private ToolbarActionContainer _leftSide;
private WebControl _rightSide;
private ToolbarActionItem _liPreText;
private Literal _litPreText;
private HtmlGenericControl _spanRowCount;
private HtmlGenericControl _spanPageCount;
private DropDownList _ddlPage;
private Literal _litPageCount;
protected override void CreateChildControls()
{
Controls.Clear();
_leftSide = new ToolbarActionContainer(); // UL
_rightSide = new WebControl(HtmlTextWriterTag.Div);
_liPreText = new ToolbarActionItem(ToolbarActionType.PreText);
_litPreText = new Literal() { Text = "Actions: " };
// Create the Toolbar Action Items
var actionItems = new List<ToolbarActionItem>(_list.Count);
foreach (var item in _list)
{
if (item.Visible)
{
var li = CreateToolbarActionItemControls(item);
actionItems.Add(li);
}
}
_spanRowCount = new HtmlGenericControl("span"); // "NNN entitie(s) found";
_spanPageCount = new HtmlGenericControl("span"); // "Page [DDL] of [LIT]";
_ddlPage = new DropDownList() { ID = "PageDDL", AutoPostBack = true, EnableViewState = false };
_litPageCount = new Literal();
_spanPageCount.Controls.Add(new Literal() { Text = "Page " });
_spanPageCount.Controls.Add(_ddlPage);
_spanPageCount.Controls.Add(new Literal() { Text = " of " });
_spanPageCount.Controls.Add(_litPageCount);
_liPreText.Controls.Add(_litPreText);
_leftSide.Controls.Add(_liPreText);
foreach(var item in actionItems)
_leftSide.Controls.Add(item);
_rightSide.Controls.Add(_spanRowCount);
_rightSide.Controls.Add(_spanPageCount);
Controls.Add(_leftSide);
Controls.Add(_rightSide);
_ddlPage.SelectedIndexChanged += PageDDL_SelectedIndexChanged;
base.CreateChildControls();
ChildControlsCreated = true;
UpdateRowCountText(); // Assigns the RowCount text to the span control _spanPageCount
UpdatePageCountText(); // The Y in "Page X of Y"
ApplyStandardClassNames();
CreatePageDDLItems(); // Populates Items in PageDDL (if required)
AssignPageDDLSelectedValue(); // Assigns the current PageDDL value (if required)
}
protected virtual ToolbarActionItem CreateToolbarActionItemControls(ToolbarItem item)
{
// Create List Item and add CssClass if required
var li = CreateToolbarActionItem(ToolbarActionType.Action);
if (item.HasCssClass)
li.CssClass = item.CssClass;
if (item.TextOnly)
{
// Text Only Action Items are added as literal text
li.Controls.Add(new Literal() { Text = item.Text });
}
else
{
var btn = new LinkButton() { Text = item.Text, ToolTip = item.ToolTip, CssClass = item.CssClass };
if (item.HasURLLink)
btn.Attributes.Add("href", item.URLLink);
else
{
btn.Click += LinkButton_Clicked;
_map.Add(btn, item); // used if posting back
// btn.Attributes.Add("href", "#");
// var js = MakeButtonJavaScript(item);
// if (js != string.Empty)
// btn.Attributes.Add("onclick", "javascript:" + js);
if(!string.IsNullOrEmpty(item.PrePostbackJSFunction))
btn.OnClientClick = $"return {item.PrePostbackJSFunction}(this);";
}
li.Controls.Add(btn);
}
return li;
}
protected virtual ToolbarActionItem CreateToolbarActionItem(ToolbarActionType type)
{
return new ToolbarActionItem(type);
}
private void CreatePageDDLItems()
{
// No DDL control created yet?
if (!ChildControlsCreated)
return;
var pageCount = PageCount;
// Current count is already correct?
if (pageCount == _ddlPage.Items.Count - 1) // -1 = "all"
return;
_ddlPage.Items.Clear();
_spanPageCount.Visible = (pageCount > 1); // Show this section only if multipage
// Not multi page?
if (pageCount <= 1)
return;
var li = new ListItem("All", "all");
_ddlPage.Items.Add(li);
for (var i = 0; i < pageCount; i++)
{
li = new ListItem((i + 1).ToString());
_ddlPage.Items.Add(li);
}
// AssignPageDDLSelectedValue() is already called whenever CreatePageDDLItems() is called!
//AssignPageDDLSelectedValue();
}
private void AssignPageDDLSelectedValue()
{
if (!ChildControlsCreated)
return;
if (ShowAllPages)
_ddlPage.SelectedValue = "all";
else
_ddlPage.SelectedValue = CurrentPage.ToString();
}
private void LinkButton_Clicked(object sender, EventArgs e)
{
System.Diagnostics.Debug.Assert(sender is LinkButton);
var button = sender as LinkButton;
var item = _map[button];
// Raise event with item's value
OnActionButtonClicked(item.Value);
}
private void PageDDL_SelectedIndexChanged(object sender, System.EventArgs e)
{
System.Diagnostics.Debug.Assert(sender == _ddlPage);
var v = _ddlPage.SelectedValue;
var newShowAllPages = (v == "all");
var newPage = newShowAllPages ? 0 : int.Parse(v);
// No Change?
if (newShowAllPages == ShowAllPages &&
(!newShowAllPages && (newPage == CurrentPage)))
return;
// Assign and raise event
ShowAllPages = newShowAllPages;
CurrentPage = newPage;
OnPageChanged(newShowAllPages, newPage);
}
private void OnActionButtonClicked(string id)
{
var evt = ActionClicked;
// check there are subscribers, and trigger if necessary
if (evt != null)
evt(this, new ToolbarActionClickedEventArgs(id));
}
private void OnPageChanged(bool showAll, int newPageNumber)
{
var evt = PageChanged;
// check there are subscribers, and trigger if necessary
if (evt != null)
evt(this, new ToolbarPageChangedEventArgs(showAll, newPageNumber));
}
}
public class ToolbarPageChangedEventArgs : EventArgs
{
public bool ShowAllPages { get; }
public int NewPageNumber { get; }
internal ToolbarPageChangedEventArgs(bool showAllPages, int newPageNumber)
{
ShowAllPages = showAllPages;
NewPageNumber = newPageNumber;
}
}
public class ToolbarActionClickedEventArgs : EventArgs
{
public string ActionValue { get; }
internal ToolbarActionClickedEventArgs(string value)
{
ActionValue = value;
}
}
public delegate void ToolbarPageChangedEventHandler(object sender, ToolbarPageChangedEventArgs args);
public delegate void ToolbarActionClickedEventHandler(object sender, ToolbarActionClickedEventArgs args);
ToolbarItem.cs
[TypeConverter(typeof(ExpandableObjectConverter))]
public class ToolbarItem
{
public ToolbarItem() : this(string.Empty, string.Empty, string.Empty, string.Empty)
{
}
public ToolbarItem(string text, string value, string jslink, string urllink)
{
Text = text;
Value = value;
JSLink = jslink;
URLLink = urllink;
CssClass = string.Empty;
ToolTip = string.Empty;
PrePostbackJSFunction = string.Empty;
Visible = true;
}
.... snip ...
}
public enum ToolbarActionType
{
None = 0,
PreText = 1,
Action = 2,
}
Related
I'm trying to create pricelist for hotel. I'm having a list of dates, and list of room types in hotel. That lists can contain random number of elements. That is created dynamically, and here is the code:
private void CreateControls() { var colIndex = 0;
var vrsteSoba = _Presenter.VrstaSobeDto.ToArray();
foreach (var bindingItem in vrsteSoba)
{
var lbl = new Label()
{
Width = LABEL_WIDTH,
Height = LABEL_HEIGHT - 5,
Left = 10,
Top = 30 + colIndex * (EDIT_BOX_HEIGHT + SPACE_BETWEEN_CONTROL),
Text = bindingItem
};
_dataPanel.Controls.Add(lbl);
colIndex++;
}
int a = 1;
foreach (var date in _Presenter.CeneTarifa)
{
int y = 0;
var panel = new Panel
{
Height = PANEL_HEIGHT * (vrsteSoba.Length-4),
Width = EDIT_BOX_WIDTH,
Left = a * (EDIT_BOX_WIDTH + SPACE_BETWEEN_CONTROL + 50),
Top = 5
};
_dataPanel.Controls.Add(panel);
var label = new Label
{
Height = EDIT_BOX_HEIGHT,
Location = new Point(0, 10),
Text = date.Datum,
Margin = new Padding(0)
};
panel.Controls.Add(label);
int index = 0;
foreach (var item in date.VrstaSobeCena)
{
var box = new TextBox();
panel.Controls.Add(box);
box.Height = EDIT_BOX_HEIGHT;
box.Width = EDIT_BOX_WIDTH;
box.Location = new Point(0, 30 + y * (EDIT_BOX_HEIGHT + SPACE_BETWEEN_CONTROL));
box.DataBindings.Add(new Binding(nameof(box.Text), date, date.Cena[index].Cena1));
y++;
index++;
}
++a;
}
_dataPanel.AutoScroll = true;
}`
Here is image of that representation.
Now I'm facing a problem of data binding. I need to bind price, two way, for each text box. And I'm stuck.
I have tried to bind it to property name, but then all boxes get same value. If I try to bind it to value via index, I'm getting error
Cannot bind to the property or column 34 on the DataSource. Parameter name: dataMember
Code below is used to fill model that is used in presenter
` private void FillCenePoTarifi() { var sobeArr = VrstaSobeDto.ToArray();
foreach (var datum in Datumi)
{
var dictionary = new Dictionary<string, decimal>();
var cene = new List<Cena>();
foreach (var item in sobeArr)
{
var tarif = _Tarife.Where(x => x.SifTarife == item).FirstOrDefault();
if (tarif != null)
_SastavTarife = HotelierServerLocal.Default.TarifaViewBlo.GetSastaveTarife(tarif.IdTarife);
//proveriti ovu logiku
var cena = _SastavTarife.Where(x => x.Cena1 != 0).Select(c => c.Cena1).FirstOrDefault();
cene.Add(new Cena { Cena1 = cena.ToString()});
dictionary.Add(item, cena);
}
var model = new CenePoTarifi
{
Datum = datum,
VrstaSobeCena = dictionary,
Cena = cene
};
CeneTarifa.Add(model);
}
}`
Finally here are classes that use as model.
` public class CenePoTarifi{
public Dictionary<string, decimal> VrstaSobeCena { get; set; } = new Dictionary<string, decimal>();
public string Datum { get; set; }
private List<Cena> _Cena;
public List<Cena> Cena
{
get => _Cena;
set
{
_Cena = value;
NotifyPropertyChanged("Cena");
}
}
public class Cena :
{
private string _Cena1;
public string Cena1
{
get => _Cena1;
set
{
_Cena = value;
NotifyPropertyChanged("Cena1");
}
}
}`
Does anyone has any suggestions?
Your question is: How to bind dynamically created text box. Here is one tested way for accomplishing that specific task.
First create some textboxes dynamically:
public MainForm()
{
InitializeComponent();
buttonRandom.Click += (sender, e) => generateRandomList();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
List<TextBox> tmp = new List<TextBox>();
for (int column = 1; column < tableLayoutPanel.ColumnCount; column++)
{
for (int row = 1; row < tableLayoutPanel.RowCount; row++)
{
TextBox textBox = new TextBox { Anchor = (AnchorStyles)0xF };
tableLayoutPanel.Controls.Add(textBox, column, row);
tmp.Add(textBox);
textBox.KeyDown += onAnyTextBoxKeyDown;
}
}
_textboxes = tmp.ToArray();
// Generate first dataset
generateRandomList();
}
TextBox[] _textboxes = null;
Then, whenever a new random list is generated, clear any old text and databindings from every TextBox before creating a new data binding for it.
public static Random Rando { get; } = new Random(2);
private void generateRandomList()
{
// Clear ALL the data + bindings for ALL the textboxes.
foreach (var textbox in _textboxes)
{
textbox.Clear();
textbox.DataBindings.Clear();
}
// Generate and create new bindings
int count = Rando.Next(1, 79);
for (int i = 0; i < count; i++)
{
var textbox = _textboxes[i];
VrstaSobeCena vrstaSobeCena =
new VrstaSobeCena{ Sobe = (Sobe)tableLayoutPanel.GetRow(textbox) };
textbox.Tag = vrstaSobeCena;
textbox.DataBindings.Add(
new Binding(
nameof(TextBox.Text),
vrstaSobeCena,
nameof(VrstaSobeCena.Cena),
formattingEnabled: true,
dataSourceUpdateMode: DataSourceUpdateMode.OnPropertyChanged,
null,
"F2"
));
// TO DO
// ADD vrstaSobeCena HERE to the Dictionary<string, decimal> VrstaSobeCena
}
}
The classes shown in your code as binding sources may not bind correctly. One issue I noticed is that the property setters are failing to check whether the value has actually changed before firing the notification. Here's an example of doing that correctly. (For testing purposes I'm showing a Minimal Reproducible Sample "mock" version of a class that implements INotifyPropertyChanged.)
enum Sobe { APP4 = 1, APP5, STUDIO, SUP, APP6, STAND, STDNT, COMSTU, LUXSTU, APP4C, APP4L, APP62, APP6L }
class VrstaSobeCena : INotifyPropertyChanged
{
decimal _price = 100 + (50 * (decimal)Rando.NextDouble());
public decimal Cena
{
get => _price;
set
{
if (!Equals(_price, value))
{
_price = value;
OnPropertyChanged();
}
}
}
Sobe _sobe = 0;
public Sobe Sobe
{
get => _sobe;
set
{
if (!Equals(_sobe, value))
{
_sobe = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Finally, one way to test the two-way binding is to intercept the [Enter] key.
private void onAnyTextBoxKeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.Enter) && (sender is TextBox textbox))
{
e.SuppressKeyPress = e.Handled = true;
VrstaSobeCena vrstaSobeCena = (VrstaSobeCena)textbox.Tag;
string msg = $"Price for {vrstaSobeCena.Sobe} is {vrstaSobeCena.Cena.ToString("F2")}";
BeginInvoke((MethodInvoker)delegate {MessageBox.Show(msg); });
SelectNextControl(textbox, forward: true, tabStopOnly: true, nested: false, wrap: true);
}
}
Create a List for storing the textbox:
List<TextBox> lstTextbox = new List<TextBox>();
Create a class object that stores the values of "Date" and "room type"
public class RoomTypeDate
{
public string RoomType = "";
public string DateRange = "";
}
Immediately after you created the textbox, assigned the RoomTypeDate info to the tag, add it to lstTextbox.
foreach (var item in date.VrstaSobeCena)
{
var box = new TextBox();
panel.Controls.Add(box);
box.Height = EDIT_BOX_HEIGHT;
box.Width = EDIT_BOX_WIDTH;
box.Location = new Point(0, 30 + y * (EDIT_BOX_HEIGHT + SPACE_BETWEEN_CONTROL));
box.DataBindings.Add(new Binding(nameof(box.Text), date, date.Cena[index].Cena1));
// add the box to the list
lstTextbox.Add(box);
// mark the box with RoomType and DateRange
RoomTypeDate rtd = new RoomTypeDate();
rtd.RoomType = "APP4"; // get the room type
rtd.DateRange = "1.6 - 30.6"; // get date range
box.Tag = rtd;
y++;
index++;
}
Now, to get and set the room price:
public void SetRoomPrice(decimal price, string roomType, string dateRange)
{
foreach (var tb in lstTextBox)
{
var rtd = (RoomTypeDate)tb.Tag;
if(rtd.RoomType == roomType && rtd.DateRange == dateRange)
{
tb.Text = price.ToString();
return;
}
}
}
public decimal GetRoomPrice(string roomType, string dateRange)
{
foreach (var tb in lstTextBox)
{
var rtd = (RoomTypeDate)tb.Tag;
if(rtd.RoomType == roomType && rtd.DateRange == dateRange)
{
return Convert.ToDecimal(rt.Text);
}
}
return 0m;
}
*code untested, might contains bugs
Code:-
public partial class Players : Form
{
public TextBox[] spelers = new TextBox[7];
List<string> spelersSpel = new List<string>();
public Form1 game = new Form1();
public Players()
{
InitializeComponent();
spelers[0] = inputSpeler1;
spelers[1] = inputSpeler2;
spelers[2] = inputSpeler3;
spelers[3] = inputSpeler4;
spelers[4] = inputSpeler5;
spelers[5] = inputSpeler6;
}
private void btnSpelers_Click(object sender, EventArgs e)
{
for (int i = 0; i < spelers.Length; i++)
{
if (spelers[i] != null)
spelersSpel.Add(spelers[i].Text);
}
foreach (TextBox item in spelers)
{
if (item != null)
spelersSpel.Add(item.Text);
}
MessageBox.Show(spelersSpel.Count.ToString());
game.ShowDialog();
}
}
I've got 6 textboxes that I've put into an array. Then I want to put this array into a form. Because I don't know how much input I get from the textboxes I don't use an array. But when I want to see how big my list is. It's saying 6. If I only type text in the first textbox the list should be 1.
What am I doing wrong?
You can get the input count by this way:
spelersSpel.Clear();
foreach (TextBox item in spelers)
{
if (item != null && item.Text.Trim() != "") //check if null or empty
spelersSpel.Add(item.Text);
}
Because (spelers[i] != null) and (item != null) does not check whether the textboxes are blank; It means the array element is null or not.
If you want to check whether your textbox is blank, you should find property Text;
if (item.Text != "")
I'm not able to use my IDE and it is not sure, but try this.
public partial class Players : Form
{
public TextBox[] spelers = new TextBox[6]; // [7];
List<string> spelersSpel = new List<string>();
public Form1 game = new Form1();
public Players()
{
InitializeComponent();
spelers[0] = inputSpeler1;
spelers[1] = inputSpeler2;
spelers[2] = inputSpeler3;
spelers[3] = inputSpeler4;
spelers[4] = inputSpeler5;
spelers[5] = inputSpeler6;
}
private void btnSpelers_Click(object sender, EventArgs e)
{
/*
// 1.
for (int i = 0; i < spelers.Length; i++)
{
if (spelers[i] != null) {
throw new Exception("NullTextBoxException");
}
else if (spelers[i].Text == "") {
// skip when the textbox is empty
continue;
}
spelersSpel.Add(spelers[i].Text);
}
*/
foreach (TextBox item in spelers)
{
if (item != null) {
// throw exception when referring textbox is null
throw new Exception("NullTextBoxException");
}
else if (item.Text == "") {
// skip when the textbox is empty
continue;
}
spelersSpel.Add(item.Text);
}
MessageBox.Show(spelersSpel.Count.ToString());
game.ShowDialog();
}
}
You are confusing the TextBox object with its Text property.
If I understand correctly you want the List<string> to contain only the text for the textboxes that are not empty, so your code should be something like this
spelersSpel.Clear();
foreach (TextBox item in spelers)
{
if (item != null && !string.IsNullOrWhiteSpace(item.Text))
spelersSpel.Add(item.Text);
}
Notice that you declare the array to contain 7 TextBoxes (index from 0 to 6) but you add only 6 textboxes to it, so you need always this check for NULL because, when you loop over your elements, you have a NULL entry in your array at index 6. So, perhaps, if you have only 6 textboxes it is better to declare the array with
public TextBox[] spelers = new TextBox[6];
Next, in the click event, you execute two loops to fill the list, this of course will duplicate the list content.
However, I think that a better approach is to use directly a List<TextBox>, work with it and get rid of the array and the List<string>
public partial class Players : Form
{
public List<TextBox> spelers;
public Form1 game = new Form1();
public Players()
{
InitializeComponent();
spelers = new List<TextBox>()
{
inputSpeler1, inputSpeler2, inputSpeler3,
inputSpeler4, inputSpeler5, inputSpeler6
}
}
private void btnSpelers_Click(object sender, EventArgs e)
{
MessageBox.Show(spelers
.Count(x => !string.IsNullOrWhiteSpace(x.Text))
.ToString());
game.ShowDialog();
}
}
In my project I have 3 user controls, those are displayed in master page. When I entered the value in textbox it doesn't getting current value, it will display previous value.
Code:
1st Data Bound:
protected void dlFirstZone_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem)) && (e.Item.DataItem != null))
{
using (GroceriesServiceClient groceriesServiceClient = new GroceriesServiceClient())
{
HomeMaster pp = (HomeMaster)e.Item.DataItem;
int prdItem = pp.ProductId;
ShoppingCart shopingCartParameter = new ShoppingCart();
//if (pp.DisplayOrder == 1)
//{
Products products = new Products();
if (basePage.BasePageWebSession != null)
{
shopingCartParameter.UserId = Convert.ToInt32(basePage.BasePageWebSession.UserId);
cartlist = groceriesServiceClient.ShoppingCart_UserProductsList(shopingCartParameter);
var td = (from c in cartlist
where c.ProductId == prdItem
select c);
if (td.ToList().Count > 0)
{
TextBox txtQtyDataview = (TextBox)e.Item.FindControl("txtQty");
txtQtyDataview.Text = td.First().Quantity.ToString();
}
}
//}
//else
}
}
}
2nd ItemCommand event handler:
protected void dlProduct_ItemCommand(object source, DataListCommandEventArgs e)
{
HomeMaster q = (HomeMaster)e.Item.DataItem;
if (e.CommandName == "AddToCart")
{
using (GroceriesServiceClient gsc = new GroceriesServiceClient())
{
ShoppingCart shoppingcart = new ShoppingCart();
shoppingcart.UserId = basePage.BasePageWebSession.UserId;
shoppingcart.UserName = basePage.BasePageWebSession.UserName;
shoppingcart.ProductId = Convert.ToInt32(Convert.ToInt32(dlProductDataView.DataKeys[e.Item.ItemIndex]));
TextBox tb1 = (TextBox)e.Item.FindControl("txtQty");
if (!string.IsNullOrEmpty(tb1.Text))
shoppingcart.Quantity = Convert.ToInt32(tb1.Text);
else
shoppingcart.Quantity = 1;
shoppingcart = gsc.ShoppingCart_InsertOrUpdate(shoppingcart);
Response.Redirect(Request.RawUrl);
}
}
}
You can use findControl to find the textbox within a user control, like this (assuming you have a textbox called tb1 in a userconrol called uc1:
me.uc1.findControl("tb1").text
The better way, though, is to expose a public function that can be called to return the value:
In UserControl, create a public function:
public function getValue() as string
return me.tb1.text
end Function
Then you can access it from any page or control that has a reference to the user control:
dim whatsMyName as string = me.uc1.getValue()
I have a list created by:
List<Song> SongList = new List<Song>();
Populated by a bunch of:
SongList.Add(new Song(songID, "Dirt", "Alice in Chains", "Rooster", "Rock", "02:32"));
The details of songs are populated into a ListBox by:
private void songTitle_TextChanged(object sender, EventArgs e)
{
i = 0;
for (; i < songTitle.Text.Length; i++)
{
songResultBox.Items.Clear();
var songResult = from song in SongList
where song.SongTitle != null && song.SongTitle.Length >= songTitle.Text.Length
&& songTitle.Text == song.SongTitle.Substring(0, i+1)
select new { sId = song.SongID, album = song.SongAlbum, artist = song.SongArtist, title = song.SongTitle,
genre = song.SongGenre, length = song.SongLength };
foreach (var item in songResult)
{
songResultBox.Items.Add(new Song(item.sId, item.album, item.artist, item.title, item.genre, item.length));
songResultBox.DisplayMember = "FullName";
songResultBox.ValueMember = "songID";
}
}
}
Question is: How would I create a button (or 4 in fact) that took the contents of the ListBox 'songResultBox' and sorted its contents by title, album, artist, genre etc.
Create the button, label it depending on what property you want to sort on, add a click event to the button, sort the items (hopefully you've maintained a list of them), then repopulate the listbox:
private bool descendingSongTitleSort = false;
private bool descendingArtistSort = false;
// Artist button clicked event
private void artistButtonClicked(object sender, EventArgs args)
{
Func<Song, IComparable> sortProp = (song => song.Artist);
sortListBox(songResultBox, descendingArtistSort, sortProp);
descendingSongTitleSort = false;
descendingArtistSort = !descendingArtistSort;
}
// Title button clicked event
private void titleButtonClicked(object sender, EventArgs args)
{
Func<Song, IComparable> sortProp = (song => song.Title);
sortListBox(songResultBox, descendingSongTitleSort, sortProp);
descendingSongTitleSort = !descendingSongTitleSort;
descendingArtistSort = false;
}
// Sorting function
private void sortListBox(
ListBox box,
bool descending,
Func<Song, IComparable> sortProperty)
{
List<Song> items = new List<Song>();
foreach (Object o in box.Items)
{
Song s = o as Song;
items.Add(s);
}
box.Items.Clear();
if(descending)
{
items = items.OrderByDescending(sortProperty).ToList();
}
else
{
items = items.OrderBy(sortProperty).ToList();
}
foreach(Song s in items)
{
box.Items.Add(s);
}
}
The descending bools aren't necessary if you don't want to worry about resorting in the opposite direction.
I would like to retain values of datatable in CheckListBox attributes method on postback also without calling the binding method it again
So I have a asp:CheckBoxList and I am binding it in
if (!IsPostBack)
{
// code for binding
}
ASP.NET
<asp:CheckBoxList ID="chkboxCandidateList" runat="server">
</asp:CheckBoxList>
This is my method to bind C#
DataTable dtCandidateName = // datatable having all specified column
if (dtCandidateName != null && dtCandidateName.Rows.Count > 0)
{
chkLstBxCandidateName.Items.Clear();
ListItem lstItem = null;
for (int i = 0; dtCandidateName.Rows.Count > i; i++)
{
lstItem = new ListItem(Convert.ToString(dtCandidateName.Rows[i]["Candidate Name"]), Convert.ToString(dtCandidateName.Rows[i]["Candidate Id"]));
lstItem.Attributes.Add("Email", Convert.ToString(dtCandidateName.Rows[i]["Email"]));
lstItem.Attributes.Add("Mobile", Convert.ToString(dtCandidateName.Rows[i]["Mobile"]));
chkLstBxCandidateName.Items.Add(lstItem);
}
}
And even I am getting values in page load first call
HTML
<span email="test#kartika.com" mobile="01111111111"><input id="ContentPlaceHolder1_chkboxCandidateList_0" type="checkbox" name="ctl00$ContentPlaceHolder1$chkboxCandidateList$0" checked="checked" value="486"><label for="ContentPlaceHolder1_chkboxCandidateList_0">Kratika Shukla</label></span>
So when I click on Submit button I am not getting value of Email and Mobile
chkboxCandidateList.Items[i].Attributes["Email"] -- getting null
I checked this article but not satisfied with the answer
try this on button Click
protected void btnSubmit_Click(object sender, EventArgs e)
{
List<string> values=new List<string>();
foreach (ListItem item in chkboxCandidateList.Items)
if (item.Selected)
values.Add(item.Text); // retrieve values here
}
this might work for you
got the solution here
just create a class
namespace customControl
{
public class ClsCheckBoxList : CheckBoxList
{
protected override object SaveViewState()
{
// create object array for Item count + 1
object[] allStates = new object[this.Items.Count + 1];
// the +1 is to hold the base info
object baseState = base.SaveViewState();
allStates[0] = baseState;
Int32 i = 1;
// now loop through and save each Style attribute for the List
foreach (ListItem li in this.Items)
{
Int32 j = 0;
string[][] attributes = new string[li.Attributes.Count][];
foreach (string attribute in li.Attributes.Keys)
{
attributes[j++] = new string[] { attribute, li.Attributes[attribute] };
}
allStates[i++] = attributes;
}
return allStates;
}
protected override void LoadViewState(object savedState)
{
if (savedState != null)
{
object[] myState = (object[])savedState;
// restore base first
if (myState[0] != null)
base.LoadViewState(myState[0]);
Int32 i = 1;
foreach (ListItem li in this.Items)
{
// loop through and restore each style attribute
foreach (string[] attribute in (string[][])myState[i++])
{
li.Attributes[attribute[0]] = attribute[1];
}
}
}
}
}
}
And in ASP.NET add reference for that
<%# Register TagPrefix="TRControls" Namespace="customControl" %>
and
<TRControls:ClsCheckBoxList ID="chkBox" runat="server">
</TRControls:ClsCheckBoxList>
for binding in code behind
if (!IsPostBack)
{
ListItem lstItem = new ListItem("vikas", "0", true);
lstItem.Attributes.Add("love", "sure");
chklstbox.Items.Add(lstItem);
chkBox.Items.Add(lstItem);
lstItem = new ListItem("kratika", "1", true);
lstItem.Attributes.Add("love", "not sure");
chklstbox.Items.Add(lstItem);
chkBox.Items.Add(lstItem);
}
that's it, now I could get the value of the attribute