c#


BindingSource.Find Multiple Columns


Is it possible to use the Find method of a BindingSource on multiple columns?
For example, say I have a gridview displaying current pets; two comboboxes, cboPetType and cboGender; and a button to create a new record into the Pet table based on the values of these two comboboxes.
Now, let's say I only want one of each PetType/Gender combination (Dog - M, Cat - F, etc.). So, if I have a Dog - M pet in my BindingSource and a user selects Dog and M from the comboboxes, I would like to stop the user to inform them that combination already exists.
In the past, I have used the BindingSource.Find method to do something similar, but, as far as I can tell, that is only good for searching one column (i.e. BindingSource.Find("PetType", cboPetType.SelectedValue);).
Is it possible to search a bindingsource based on multiple columns? If not, any suggestions to achieve my desired result? Any advice is greatly appreciated!
No, unfortunately this isn't possible. While it's likely that given a particular data source that such a search would be fairly simple, doing it in a more generic way (as the BindingSource would) is a little less transparent. For one, the syntax would be less than obvious. Here's a somewhat contrived solution:
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;
}
You can call it like this:
BindingSource source = // your BindingSource, obviously
int index = source.Find(
new Key { PropertyName = "PetType", Value = "Dog" },
new Key { PropertyName = "Gender", Value = "M" });
Bear in mind that for this to be usable, you really need a smarter comparison algorithm, but I'll leave that as an exercise to the reader. Checking for an implementation of IComparable would be a good start. Nonetheless, the concept should carry through regardless of that particular point of implementation.
Note that this won't take advantage of any of the possible performance optimizations that might be implemented by the underlying data source, whereas the single column Find would.
Another simpler solution, in case someone runs into the same issue. This works when the BindingSource is a 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
This is my version based on the above examples. It works very well.
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
I call it thus:
e.Cancel = clsBSHelpers.Find(CastingBedBindingSource, _
New clsBSHelpers.Key("PlantID", m_PlantID), _
New clsBSHelpers.Key("LineBedNUmber", m_LineBedNumber))
Hope this helps those that like it simple.
The more simple solution is by using Extension Method:
var id1 = "id1";
var id2 = "id2";
var data = bindingSource1.Cast<DataModelType>().Single(r => r.ID1 == id1 && r.ID2 == id2);
bindingSource1.Position = bindingSource1.IndexOf(data);

Related Links

C# Display SQL data to HTML Textbox based on Textbox ID
using ffmpeg in Azure function to cut files using c#
Adding columns to AspNetUserClaims in ASP.NET Identity
DocumentComplete Event - Add function fails
C# Discord.Net bot deleting messages no responde
Use the for attribute of a label to reference a control inside a repeater
ASP.NET passing List back to controller from IEnumerable #model inside Table header ActionLink with non-indexing
Moq a concrete class method call
Serial Port Coin Acceptor programming c#
Error while sending web push notification using fiddler
ASP.NET c# searching data between two date using the calendar control and report viewer
Creating a static array with already existing objects in C# [duplicate]
C# Object reference not set to an instance of an object. [duplicate]
How to return and retrieve object value in C#?
Google Offline Conversion Adwords Upload Error
C# unit testing for a NotFound via a GET

Categories

HOME
c#
casting
conceptual
crm
redhawksdr
opengl-es
sugarcrm
docker-compose
sitemap
wkhtmltopdf
ethereum
chef-recipe
watson-dialog
element
webseal
appsettings
google-closure-compiler
dat.gui
multibinding
vivado-hls
aiml
xforms
react-jsx
cherrypy
mattermost
beaker-notebook
opengraph
tcpdf
oracle-golden-gate
scrapy-spider
aws-certificate-manager
sasl
stack-trace
workflow-foundation
boosting
pushpad
openoffice-impress
edsdk
drawrect
login-required
ng2-bootstrap
circle
traitsui
apache-falcon
wit-ai
minitest
certbot
outlook-2010
instances
nscollectionview
mockserver
keychain
file-descriptor
compiled-query
ape-phylo
java-5
compiler-warnings
web-technologies
python-venv
gridgain
synchronized
confluent
openidm
openpgp.js
sp
overhead
zedgraph
acceleo
vertex-shader
lattice
portaudio
optional-parameters
easy68k
dbi
xcode7.1
rowname
konakart
cosign-api
key-value-store
jmh
calc
web-performance
skscene
ruby-1.8.7
commercetools
play-json
transbase
log4cxx
openhab
eggplant
static-files
javadb
system.io.packaging
yosemite
gnip
nsmutableurlrequest
serializer
pyalgotrade
reactjs-native
pidgin
infor-eam
android-jack-and-jill
typography
backbone-views
mosix
generator-expression
phone-state-listener
yii-components
motorola-droid
advanceddatagrid
nsundomanager
code-organization
recess
sessiontracking
meego-harmattan
html5-animation
fxcopcmd
subdirectories
table-valued-parameters
silverlight-2.0
dynamic-scope
rpxnow
scala-designer

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App