BindingSource.Find多列

时间:2009-11-19 22:25:34

标签: c# winforms find bindingsource multiple-columns

是否可以在多列上使用BindingSource的Find方法?

例如,假设我有一个显示当前宠物的网格视图;两个组合框,cboPetType和cboGender;以及一个按钮,根据这两个组合框的值在Pet表中创建一条新记录。

现在,假设我只想要每个PetType / Gender组合中的一个(Dog-M,Cat-F等)。所以,如果我在BindingSource中有一个Dog-M宠物,并且用户从组合框中选择了Dog和M,我想阻止用户通知他们组合已经存在。

过去,我使用BindingSource.Find方法做类似的事情,但据我所知,这只适用于搜索一列(即BindingSource.Find(“PetType”,cboPetType.SelectedValue) );)

是否可以根据多个列搜索bindingsource?如果没有,任何建议,以达到我想要的结果?非常感谢任何建议!

5 个答案:

答案 0 :(得分:3)

不,不幸的是,这是不可能的。虽然给定一个特定的数据源可能会使这样的搜索变得相当简单,但是以更通用的方式(如BindingSource那样)进行此操作会稍微透明一些。首先,语法不太明显。这是一个有点人为的解决方案:

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

您可以这样称呼它:

BindingSource source = // your BindingSource, obviously 

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

请记住,为了使其可用,你真的需要一个更智能的比较算法,但我会将其作为练习留给读者。检查IComparable的实施将是一个良好的开端。尽管如此,无论特定的实施点如何,这个概念都应该贯彻。

请注意,这不会利用底层数据源可能实现的任何可能的性能优化,而单列Find会实现。

答案 1 :(得分:2)

另一个更简单的解决方案,以防有人遇到同样的问题。这在BindingSource是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

答案 2 :(得分:0)

这是基于以上示例的我的版本。它运作得很好。

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

我这么称呼它:

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

希望这有助于那些喜欢它的人。

答案 3 :(得分:0)

更简单的解决方案是使用扩展方法:

 $('.child').mousedown(function(){
   //what can I write here to prevent parent's click event from fireing?
   //I've tried event.stopPropagation() as well as
   //event.stopImmediatePropagation() already 
   });

 $('.parent').on('click',function(){...})

答案 4 :(得分:0)

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