Question

I'm new to generics so I'm probably just doing this completely wrong but here goes: I have a small collection of controls that I'm combining together into a user control. It looks like it'll work as expected but the uc needs to be generic. Within the uc I have couple listboxes (and some buttons). Those list boxes and the uc must be able to take any number of generic lists. (Ie List<user>, List<group>, List<platform>, etc and then return the changes to that generic list. I think I have it accepting the generic list alright but not sure how to get a generic list back.

Control:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="AddRemoveList.ascx.cs" Inherits="NSDC_Supply.UserControls.AddRemoveList" %>
<table>
    <tr>
        <td><asp:ListBox ID="ListBox1" Width="150px" Height="100px" SelectionMode="Single" runat="server" /></td>
        <td><asp:Button ID="AddUser" runat="server" Text="<<" CausesValidation="false" onclick="AddUser_Click" /></td>
        <td><asp:Button ID="RemoveUser" runat="server" Text=">>" CausesValidation="false" onclick="RemoveUser_Click" /></td>
        <td><asp:ListBox ID="ListBox2" Width="150px" Height="100px" SelectionMode="Single" runat="server" /></td>
    </tr>
</table>

Code Behind:

public partial class AddRemoveList : System.Web.UI.UserControl 
{
    public T EditedList { get; set; }  //Obviously this won't work

    protected void Page_Load(object sender, EventArgs e)
    {}

    public void FillListBox<T>(T collection1, T collection2, string val, string text)
    {
        ListBox1.DataSource = collection1;
        ListBox1.DataTextField = text;
        ListBox1.DataValueField = val;
        ListBox1.DataBind();

        ListBox2.DataSource = collection2;
        ListBox2.DataTextField = text;
        ListBox2.DataValueField = val;
        ListBox2.DataBind();
    }

    protected void AddItem_Click(object sender, EventArgs e)
    {
        if (ListBox2.SelectedIndex > -1)
        {
            ListBox1.Items.Add(ListBox2.SelectedItem);
            EditedList.Add(ListBox2.SelectedItem);
            ListBox2.Items.RemoveAt(ListBox2.SelectedIndex);
            ListBox1.ClearSelection();
        }
    }

    protected void RemoveItem_Click(object sender, EventArgs e)
    {
        if (ListBox1.SelectedIndex > -1)
        {
            ListBox2.Items.Add(ListBox1.SelectedItem);
            EditedList.Remove(ListBox2.SelectedItem);
            ListBox1.Items.RemoveAt(ListBox1.SelectedIndex);
            ListBox2.ClearSelection();
        }
    }

}

So first I populating the uc:

private void GridView1_SelectedIndexChanged(...)
{
    List<user> myUsers = selectedGroup.users.ToList();
    List<user> masterUserList = uc.GetAllUsers().OrderBy(g => g.full_name).ToList();

    UserControls.AddRemoveList ucarl = ((UserControls.AddRemoveList)FormView1.Controls[0].FindControl("ucAddRemoveList"));
    ucarl.FillListBox(myUsers, masterUserList, "id", "full_name");
}

Then after editing the listboxes in the uc, I try updating the entity:

protected void FormView1_ItemUpdate(Object sender, FormViewUpdateEventArgs e)
{
    network_group editedGroup = new network_group();
    editedGroup.id = Convert.ToInt32(((Label)selectedControls.FindControl("lblid")).Text);
    editedGroup.full_name = ((TextBox)selectedControls.FindControl("txtfull_name")).Text;
    editedGroup.distribution_list_email = ((TextBox)selectedControls.FindControl("txtemail")).Text;
    UserControls.AddRemoveList ucarl = ((UserControls.AddRemoveList)FormView1.Controls[0].FindControl("ucAddRemoveList"));

    editedGroup.users.Add(ucarl);   //psudocode here
    ctx.SaveChanges();
}

If I remove all calls to EditedList, it works but how do I get the generic EditedList out of the uc?

UPDATE: The answers I’m getting seem like they’re trying to solve a different issue…I think. So here’s an update of what I’m trying to do:

I currently have two ListBoxes on a page. I bind a list of objects populated from EntityFramework entities to the ListBoxes. ListBox1 is a child collection of entity objects for the entity object I’m currently looking at. ListBox2 is a collection of all the entries possible in the child entity object. So for this example, I’m looking at an instance of the Group entity. ListBox1 is all the Users associated with this Group and ListBox2 is all the Users in the company.

Between the ListBoxes are add/remove buttons to move items back and forth between the two. (So I can add or remove Users to/from Groups, Devices to/from Sites, etc using the AddItem_Click and RemoveItem_Click events. Then on FormView1_ItemUpdate event I'm grabbing the collection in ListBox1 (the edited list of Users) and saving it to the DB.

But because I will be doing this almost exact functionality 9+ times, I'm trying to abstract the 4 controls into a uc. This way I can pass in any two List collections, the text and value fields I want to bind for any given object, do my adding/removing and then get a modified List back.

So my question isn’t about getting the items from one ListBox to the other, it’s about getting the edited List collection from ListBox1 back when I’m done. Does this help? Does it change any of the answers? Sorry if I was too vague.

Was it helpful?

Solution

The easiest way I can think of would be to add an extension method that does this for you. If all of your objects implement an interface that has the properties id and fullname such as:

public interface IListableObject
{
    string id { get; set; }
    string full_name { get; set; }
}

Then you can write an extension method for the ListBox control:

public static List<T> GetListFromListBoxControl<T>(this ListBox source) where T: IListableObject, new()
{
    var returnValue = new List<T>();

    foreach(var item in source.Items)
    {
        returnValue.Add(new T() {
            id = item.Value,
            full_name = item.Text    
        });
    }

    return returnValue;
}

Treat this as pseudo-code (I haven't tested it), but the idea is sound. Then you'd just be able to get your list from the ListBox directly:

var newList_of_users = ListBox.GetListFromListBoxControl<user>();

If interfaces and extension methods aren't your bags of tea, then you could always just write a static method somewhere and do the parsing on a one to one basis.

public static List<user> GetUsersFromListBox(ListBox source)
{
    var returnValue = new List<user>();

    foreach(var item in source.Items)
    {
        returnValue.Add(new user() {
            id = item.Value,
            full_name = item.Text    
        });
    }

    return returnValue;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top