Question

Est-il possible d'utiliser la méthode Find d'un BindingSource sur plusieurs colonnes?

Par exemple, que j'ai un gridview affichage animaux actuels; deux comboboxes, cboPetType et cboGender; et un bouton pour créer un nouvel enregistrement dans la table Pet sur la base des valeurs de ces deux listes déroulantes.

Maintenant, disons que je veux seulement un de chaque PetType / combinaison de genre (Chien - M, Cat - F, etc.). Donc, si j'ai un chien -. M animal de compagnie dans mon BindingSource et un utilisateur sélectionne le chien et M des comboboxes, je voudrais arrêter l'utilisateur de les informer que la combinaison existe déjà

Dans le passé, je l'ai utilisé la méthode BindingSource.Find pour faire quelque chose de similaire, mais, pour autant que je peux dire, c'est seulement bon pour la recherche d'une colonne (c.-à-BindingSource.Find ( « PetType », cboPetType.SelectedValue ).)

Est-il possible de rechercher un BindingSource basé sur plusieurs colonnes? Dans le cas contraire, des suggestions pour atteindre mon résultat désiré? Tout conseil est grandement appréciée!

Était-ce utile?

La solution

Non, malheureusement, ce n'est pas possible. Bien qu'il est probable que, compte tenu d'une particulier source de données que cette recherche serait assez simple, il fait d'une manière plus générique (comme le ferait BindingSource) est un peu moins transparent. D'une part, la syntaxe serait moins évidente. Voici une solution quelque peu artificielle:

public class Key
{
    public string PropertyName {get; set;}
    public object Value {get; set;}
}

public static int Find(this BindingSource source, params Key[] keys)
{
    PropertyDescriptor[] properties = new PropertyDescriptor[keys.Length];

    ITypedList typedList = source as ITypedList;

    if(source.Count <= 0) return -1;

    PropertyDescriptorCollection props;

    if(typedList != null) // obtain the PropertyDescriptors from the list
    {
        props = typedList.GetItemProperties(null);
    }
    else // use the TypeDescriptor on the first element of the list
    {
        props = TypeDescriptor.GetProperties(source[0]);
    }

    for(int i = 0; i < keys.Length; i++)
    {
        properties[i] = props.Find(keys[i].PropertyName, true, true); // will throw if the property isn't found
    }

    for(int i = 0; i < source.Count; i++)
    { 
        object row = source[i];
        bool match = true;

        for(int p = 0; p < keys.Count; p++)
        {
            if(properties[p].GetValue(row) != keys[p].Value))
            {
                match = false;
                break;
            }
        }

        if(match) return i;
    }

    return -1;
}

Vous pouvez l'appeler comme ceci:

BindingSource source = // your BindingSource, obviously 

int index = source.Find(
    new Key { PropertyName = "PetType", Value = "Dog" },
    new Key { PropertyName = "Gender", Value = "M" });

Gardez à l'esprit que pour que cela soit utilisable, vous vraiment ont besoin d'un algorithme de comparaison plus intelligent, mais je vais laisser cela comme un exercice au lecteur. Vérification d'une mise en œuvre de IComparable serait un bon début. Néanmoins, le concept devrait mener à bien indépendamment de ce point particulier de la mise en œuvre.

Notez que cela ne profitera pas de l'une des optimisations de performance possibles qui pourraient être mises en œuvre par la source de données sous-jacentes, alors que la seule colonne Find serait.

Autres conseils

Une autre solution plus simple, au cas où quelqu'un se jette dans la même question. Cela fonctionne lorsque le BindingSource est un DataView:

MyBindingSource.Sort = "Column1,Column2"
Dim underlyingView As DataView = DirectCast(MyBindingSource.List, DataView)
Dim searchVals As New List(Of Object)
searchVals.Add("SearchString1")
searchVals.Add("SearchString2")

Dim ListIndex as Integer = underlyingView.Find(searchVals.ToArray)

If ListIndex >=0 Then
    MyBindingList.Position = ListIndex
Else
    'No matches, so what you need to do...
End If

Ceci est ma version basée sur les exemples ci-dessus. Il fonctionne très bien.

Public Class clsBSHelpers

    Public Structure Key

        Public PropertyName As String
        Public Value As Object

        Sub New(ByVal pPropertyName As String, ByVal pValue As Object)
            PropertyName = pPropertyName
            Value = pValue
        End Sub

    End Structure

    Public Shared Function Find(ByVal Source As BindingSource, ByVal ParamArray keys As Key()) As Boolean

        Dim sb As New Text.StringBuilder
        For i As Integer = 0 To keys.Length - 1
            If sb.Length > 0 Then
                sb.Append(",")
            End If
            sb.Append(keys(i).PropertyName)
        Next

        Source.Sort = sb.ToString
        Dim underlyingView As DataView = DirectCast(Source.List, DataView)
        Dim searchVals As New List(Of Object)
        For i As Integer = 0 To keys.Length - 1
            searchVals.Add(keys(i).Value)
        Next

        Dim ListIndex As Integer = underlyingView.Find(searchVals.ToArray)

        If ListIndex >= 0 Then
            Source.Position = ListIndex
            Find = True
        Else
            Find = False
            'No matches, so what you need to do...
        End If

        Return Find

    End Function

End Class

Je l'appelle ainsi:

e.Cancel = clsBSHelpers.Find(CastingBedBindingSource, _
                             New clsBSHelpers.Key("PlantID", m_PlantID), _
                             New clsBSHelpers.Key("LineBedNUmber", m_LineBedNumber))

Espérons que cela aide ceux qui aiment les choses simples.

La solution la plus simple en utilisant la méthode d'extension:

var id1 = "id1";
var id2 = "id2";

var data = bindingSource1.Cast<DataModelType>().Single(r => r.ID1 == id1 && r.ID2 == id2);
bindingSource1.Position = bindingSource1.IndexOf(data);
var sorcobj = SorcBs.Current as Data.Student;

if (sorcobj == null) return;

TrgtBs.Position = TrgtBs.List.IndexOf(TrgtBs.List.OfType<Data.Student>().FirstOrDefault(s => s.NAME == sorc.NAME));
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top