Linking a multi-user ListBox in a FormView control
I have a Multiselect ListBox inside a FormView. I can't figure out how to set up data binding for it.
I can fill in the list ok. If listbox was the only choice, I could use say SelectValue='<%#Bind("col")%>'
and that works great. Is there something I can bind for a multi-selector list? I tried manually DataBinding by handling the DataBinding event on the list and setting the selected property on the appropriate items. Unfortunately, there are no items in the list during the DataBinding event. The closest I have found is to store a value that determines which items to select during the DataBinding, and then use that value in the FormViews DataBinding event to select the correct items that seem to be hacked to me.
Is there a better way?
EDIT:
To clarify what I am doing now ...
I am using FormViews ItemCreated event to save FormView DataItem. Then in the FormView DataBound event, I find the list and manually set the selected items. It doesn't seem like I need to store a value like this, and I'm guessing there is a better way to do it that I just can't see.
a source to share
When I did this before, I set a datasource from a list, bound it, then enumerated the list of items in the list, and set .Selected to true for each item that matched my criteria. or values. I'm not sure if this is the most efficient, but for the small lists I have worked with, it certainly worked great.
a source to share
What I ended up with was ditching the ListBox and I settled on a TreeView since it really helped my goals.
Before that though I wrote this function to select the current items and I called it from Page_PreRender because the binding is complete and I could get the controls I needed.
protected void SelectCategories()
{
ListBox lb = (ListBox)fvProduct.FindControl("lstCategory");
Product product = (Product)pdc.Products.Where(a => a.Sku == txtSku.Text).FirstOrDefault();
var c = pdc.ProductCategories.Where(b => b.ProductId == product.ProductId);
if (lb != null && lb.Items.Count > 0)
{
foreach (ProductCategory cat in c)
{
foreach (ListItem li in lb.Items)
{
if (cat.CategoryId == Convert.ToInt32(li.Value))
{
li.Selected = true;
}
}
}
}
}
And then when I need to update from the ListBox, I called the following code from the FormView.ItemUpdating event.
protected void UpdateCategories()
{
ListBox lb = (ListBox)fvProduct.FindControl("lstCategory");
Product product = (Product)pdc.Products.Where(a => a.Sku == txtSku.Text).FirstOrDefault();
if (lb != null && lb.Items.Count > 0)
{
foreach (ListItem li in lb.Items)
{
ProductCategory pc = new ProductCategory();
pc = (ProductCategory)pdc.ProductCategories.Where(d => d.CategoryId == Convert.ToInt32(li.Value) && d.ProductId == product.ProductId).FirstOrDefault();
if (pc == null)
{
if (li.Selected == true)
{
//note: if li is selected but pc is null then insert new record .
pc = new ProductCategory();
pc.ProductId = product.ProductId;
pc.CategoryId = Convert.ToInt32(li.Value);
pdc.ProductCategories.InsertOnSubmit(pc);
pdc.SubmitChanges();
}
}
else
{
if (li.Selected == false)
{
//note: if li is not selected but pc is not null then remove record.
pdc.ProductCategories.DeleteOnSubmit(pc);
pdc.SubmitChanges();
}
}
}
}
}
It was really bad, but it worked. Maybe I could improve it if I compiled a linq query , but I never waited. I understand from your comment above that you could solve your own approach to the problem, so I am only adding this answer if it can help future lost souls like me.
In the end, TreeView became the best tool for me, so I didn't have to do it anyway. While this is the start of a new adventure, since you cannot easily bind a TreeView to a LinqDataSource, it is a story for another day.
a source to share