Frage

Ist es möglich, die Methode Suchen eines Binding auf mehreren Spalten zu benutzen?

Zum Beispiel, sagen, ich habe ein gridview aktuelle Haustiere anzeigt; zwei Comboboxen, cboPetType und cboGender; und eine Schaltfläche, um einen neuen Datensatz in die Pet-Tabelle zu erstellen auf der Grundlage der Werte dieser beiden Comboboxen.

Nun lassen Sie uns sagen, ich will nur eine von jeder PetType / Geschlecht Kombination (Hund - M, Katze - F, etc.). Also, wenn ich einen Hund haben -. M Haustier in meiner Binding und wählt ein Benutzer Hund und M aus den Comboboxen, würde Ich mag den Benutzer zu stoppen, sie zu informieren, dass Kombination bereits vorhanden

In der Vergangenheit habe ich die BindingSource.Find Methode verwendet, um etwas ähnliches zu tun, aber, soweit ich das beurteilen kann, die für die Suche einer Spalte nur gut ist (dh BindingSource.Find ( „PetType“, cboPetType.SelectedValue );).

Ist es möglich, eine Binding basierend auf mehreren Spalten suchen? Wenn nicht, irgendwelche Vorschläge meine gewünschte Ergebnis zu erzielen? Jede Beratung ist sehr zu schätzen!

War es hilfreich?

Lösung

Nein, das ist leider nicht möglich. Während es ist wahrscheinlich, da ein insbesondere Datenquelle, dass eine solche Suche ziemlich einfach sein würde, es in eine allgemeinere Art und Weise zu tun (wie die BindingSource würde) etwas weniger transparent ist. Zum einen wäre die Syntax weniger als offensichtlich. Hier ist eine etwas gekünstelt Lösung:

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;
}

Sie können es so nennen:

BindingSource source = // your BindingSource, obviously 

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

Beachten Sie, dass für diese verwendbar zu sein, Sie wirklich brauchen einen intelligenteren Vergleichsalgorithmus, aber ich lasse das als eine Übung für den Leser. Überprüfen für eine Implementierung von IComparable wäre ein guter Anfang sein. Dennoch sollte das Konzept durchsetzen, unabhängig von diesem speziellen Punkt der Umsetzung.

Beachten Sie, dass dies nicht von Vorteil jeder der möglichen Performance-Optimierungen stattfinden wird, die durch die zugrunde liegende Datenquelle implementiert werden könnten, während die einzelne Spalte Find würde.

Andere Tipps

Eine andere einfachere Lösung, falls jemand läuft in der gleichen Ausgabe. Dies funktioniert, wenn der Binding ist ein 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

Dies ist meine Version auf die obigen Beispiele basieren. Es funktioniert sehr gut.

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

Ich nenne es so:

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

Hope dies hilft denen, die wie es einfach.

Die einfachere Lösung ist die Verwendung von Erweiterungsmethode:

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));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top