1

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

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

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

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

是否可以基于多列搜索绑定源?如果没有,有什么建议可以达到我想要的结果吗?任何意见是极大的赞赏!

4

5 回答 5

2

不,不幸的是,这是不可能的。虽然给定一个特定的数据源,这样的搜索可能会相当简单,但以更通用的方式(就像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可以。

于 2009-11-19T22:40:25.220 回答
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
于 2010-02-24T19:41:28.253 回答
1

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

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

希望这可以帮助那些喜欢它简单的人。

于 2012-11-06T17:03:45.040 回答
0

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

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

var data = bindingSource1.Cast<DataModelType>().Single(r => r.ID1 == id1 && r.ID2 == id2);
bindingSource1.Position = bindingSource1.IndexOf(data);
于 2016-07-22T02:38:03.587 回答
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));
于 2018-05-10T08:34:09.647 回答