Pergunta

É possível usar o método de localização de um BindingSource em várias colunas?

Por exemplo, digamos que eu tenha uma GridView exibindo animais de estimação atuais; dois combosbóxos, CbopeTtype e CBOGENDER; e um botão para criar um novo registro na tabela de animais de estimação com base nos valores desses dois combustos.

Agora, digamos que eu só quero uma de cada combinação de pettype/gênero (cachorro - M, Cat - F, etc.). Então, se eu tiver um cachorro - M PET no meu BindingSource e um usuário seleciona o cachorro e M das ComboBoxes, gostaria de impedir o usuário para informá -los de que a combinação já existe.

No passado, usei o método BindingSource.Find para fazer algo semelhante, mas, até onde eu sei, isso é bom apenas para pesquisar uma coluna (ou seja, Bindingsource.find ("Pettype", CbopeTtype.SelectectedValue);) .

É possível pesquisar um BindingSource com base em várias colunas? Caso contrário, alguma sugestão para alcançar o resultado desejado? Qualquer conselho é muito apreciado!

Foi útil?

Solução

Não, infelizmente isso não é possível. Embora seja provável que dado um especial fonte de dados que essa pesquisa seria bastante simples, fazendo isso de uma maneira mais genérica (como o BindingSource seria) é um pouco menos transparente. Por um lado, a sintaxe seria menos do que óbvia. Aqui está uma solução um tanto artificial:

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

Você pode chamá -lo assim:

BindingSource source = // your BindingSource, obviously 

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

Tenha em mente que, para que isso seja utilizável, você verdade Precisa de um algoritmo de comparação mais inteligente, mas vou deixar isso como um exercício para o leitor. Verificando uma implementação de IComparable seria um bom começo. No entanto, o conceito deve ser realizado independentemente desse ponto de implementação específico.

Observe que isso não aproveitará nenhuma das possíveis otimizações de desempenho que podem ser implementadas pela fonte de dados subjacente, enquanto a coluna única Find gostaria.

Outras dicas

Outra solução mais simples, caso alguém encontre o mesmo problema. Isso funciona quando o BindingSource é um 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

Esta é a minha versão com base nos exemplos acima. Funciona muito bem.

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

Eu chamo assim:

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

Espero que isso ajude aqueles que gostam simples.

A solução mais simples é usando o método de extensão:

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));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top