0

I have a project which has a checkbox list that contains code and name of various countries, for example: value =91, country=india etc. taking input from user, I want to add new value + country name to the existing checkbox list. I have the following code as of now. the list is made as follows:

<asp:CheckBoxList ID="cblCountry" runat="server">
                    <asp:ListItem Value="91" Text="India"></asp:ListItem>
                    <asp:ListItem Value="92" Text="Nepal"></asp:ListItem>
                    <asp:ListItem Value="93" Text="Sri Lanka"></asp:ListItem>
                    <asp:ListItem Value="94" Text="China"></asp:ListItem>
                    <asp:ListItem Value="95" Text="Pakistan"></asp:ListItem>
                    <asp:ListItem Value="96" Text="Bangladesh"></asp:ListItem>
                </asp:CheckBoxList>

I have set up validation to not allow duplicate value or text as follows in c# code:

 for (int i = cblCountry.Items.Count - 1; i >= 0; i--)
    {
        if(liCountry.Value==cblCountry.Items[i].Value || liCountry.Text==cblCountry.Items[i].Text.Trim())
        {
            lblMessage.Text ="This code or Name is already taken for another Country.";
            flag = true;
            break;
        }
        else
        {
            flag = false;
        }
    }

I have to implement the logic that allows new entry only if both value and name of country have never been repeated. the entry should be denied if either value or code or both are repeated. This is to be implemented with the help of CheckBoxList.Items.Contains() method, but since this method compares the whole item, I don't know how to compare either duplicate value or duplicate name separately. Please help me out with this. Thanks.

2 Answers2

1

You could query the objects by a composite key and check if there are any results.

A Linq .Any filter is an efficient method to do such a task.

e.g.

int newValue = 1;
string newText = "Foo";
var alreadyExists = cblCountry.Items.Any(x => x.Value == newValue  && x.Text == newText );

This will return true if both the Text and Value already exist in the same combination. Otherwise false if it's unique.

EDIT: Original Answer allows duplicates but not in the same combination. If both must be unique then an OR instead of AND can be used.

var alreadyExists = cblCountry.Items.Any(x => x.Value == newValue || x.Text == newText );

If you want to provide more meaningful errors back, then you can determine the entry which cased the duplicate by filtering it out instead of getting a simple boolean back.

e.g.

var theDuplicate = cblCountry.Items.Where(x => x.Value == newValue || x.Text == newText).FirstOrDefault();
if (theDuplicate != null)
{
    string errorMessage = $"Duplicate record where value is {theDuplicate.Value} or text is {theDuplicate.Text}";
}

Edit: Add extension method as it looks like the op wants a more fluent syntaxt.

We can add our own custom methods onto an existing items by creating an extension method which might look something like this. One would allow you to pass any expression in on the fly and the other is specifically for the text/value situation in question.

e.g.

public static class ListItemExtensitons 
{
    // this one will let us pass in any func, but it's essentially just an alias for .Any as it does the exact same thing.
    public static bool Contains(this List<ListItem> myListItems, Func<ListItem, bool> func)
    {
        return myListItems.Any(func);
    }

    public static bool ContainsValueOrText(this List<ListItem> myListItems, string value, string text)
    {
        return myListItems.Any(x => x.Text == text || x.Value == value);
    }

    // or if you have a new ListItem already instantiated that you want to compare:
    public static bool ContainsSameValueOrText(this List<ListItem> myListItems, ListItem compareTo)
    {
        return myListItems.Any(x => x.Text == compareTo.Text || x.Value == compareTo.Value);
    }
}
Joe_DM
  • 985
  • 1
  • 5
  • 12
  • I get this concept quite clearly and this does help, thanks for that, but the problem still remains because I am supposed to check for uniqueness of both value and text using something like this: CheckBoxList.Items.Contains() . I have tried adding the newly created item in the method as parameter, but it checks the whole item, not value and name separately. If there is a solution to that, it would be of great help. Thanks again. – Chaitanya Bathia Sep 05 '20 at 14:54
  • It sounds like you want to override the default behavior of `Contains` to change it's definition of equality. I don't think it's a good solution. If this is what you want then I dont have the exact answer but I think you'll need to override some of default `Equals` functions and probably need to implement some additional interfaces on your object such as `IComparable` and `IEquatable`. By changing the definition of equals you can basically tell `Contains` that anything with either the same text or value is equal, but then it would also show up as equal with a basic `==` operation. – Joe_DM Sep 06 '20 at 02:34
  • @ChaitanyaBathia I added some examples of extension methods into my answer, maybe this is more what you want. Let me know. – Joe_DM Sep 06 '20 at 02:48
0

You can try a method like this.

    private bool AddNewCountry(string countryName, string countryId)
    {
        var country = cblCountry.Items.FindByValue(countryId);
        var countryKey = cblCountry.Items.FindByText(countryName);
        if (country != null)
        {
            return false; //This means there cblCountry contains country with the given name so we cannot proceed
        }
        if (countryKey != null)
        {
            return false; //This means there cblCountry contains country with the given key or Id so we cannot proceed
        }

        return true;
    }

And use it like this in your code

    if (AddNewCountry("test", "1"))
    {
       lblResult.Text = "Yes Add It";
    }
    else
    {
       lblResult.Text = "No we can't";
    }
Gnyasha
  • 658
  • 11
  • 19
  • I get this concept quite clearly and this does help, thanks for that, but the problem still remains because I am supposed to check for uniqueness of both value and text using something like this: CheckBoxList.Items.Contains() . I have tried adding the newly created item in the method as parameter, but it checks the whole item, not value and name separately. If there is a solution to that, it would be of great help. Thanks again. – Chaitanya Bathia Sep 05 '20 at 14:55
  • Hi So you want to use the method like this `cblCountry.Items.Contains(new ListItem("India", "9"))` If so It seems to fail and I think you may need to look for other alternatives. – Gnyasha Sep 05 '20 at 15:43