Passing more than 1 argument to a converter - wpf

Question: How can you pass an instance of an object from the view model to a converter along with the value to be converted to a converter?
Info: I'm working on an inventory program for people on our factory floor who receive incoming shipments. While receiving a shipment they will mark down who the shipping company was and who the driver was. To do this I want to have set up a pair of combo boxes. When they select the shipper combo box and select the shipper the driver combo box will reflects this change.
My plan is to have a list of shippers (who have a list of drivers) in my ShipmentViewModel that the shipper combo box binds to. This list of shippers is only a list of GUID that i pull up from the database. the shipment's shipper will have a separate property for the shipper that is selected as well as the driver selected.
What I would like to do is pass the instance of the shipper list to the converter along with the GUID of the shipper(Gotten from the ShipmentVM). The converter compares the GUID to the list of shippers and returns to the combo box a instantiation of the ShipperVM. the driver combo box is the bound to the ShipperVM's list of drivers. Pass this list along with the driver's GUID(Also gotten from the ShipmentVM) to another converter which returns the driver's name.
I'm programing in Visual Basic and XAML according to the M-V-VM schema.
P.S. Saying "You can't pass more than 1 argument to a converter." is a totally legitimate response. I just need confirmation. I'm starting to think that this is the case...

If you need to pass multiple "things" to a converter, what you actually want is a MultiValueConverter, which can accept N number of input values.
http://msdn.microsoft.com/en-us/library/system.windows.data.imultivalueconverter.aspx

Related

How to quickly populate a combobox with database data (VCL)

I have read all sorts of documents across the web about what should be a farly common and painless implementation. Since I have found no consistent and slick reply (even the Embarcadero website describes some properties wrong!) I am going to post a "short" howto.
Typical, frequent use case: the developer just wants to painlessy show a couple of database-extracted information in a combo box (i.e. a language selection), get the user's choice out of it and that's it.
Requirements:
Delphi, more or less any version. VCL is covered.
A database table. Let's assume a simple table with an id and value fields.
A DataSet (including queries and ClientDataSets).
A DataSource linked to the DataSet.
A TDBLookupComboBox linked to the DataSource that shall show a list of values and "return" the currently selected id.
Firstly, we decide whether the sort order is the one we want or not and if all the items in that table must be shown. Most often, a simple ORDER BY clause or a DataSet index will be enough. In case it's not, we may add a sort_order field and fill it with integers representing our custom sort order. In case we want to show just some items, we add a visible or enabled field and use it in our SQL. Example:
SELECT id, value
FROM my_database_table
WHERE visible = 1
ORDER BY sort_order
I have defined visible as INTEGER and checking it against 1 and not TRUE because many databases (including the most used SQLite) have little support for booleans.
Then an optional but surprisingly often nice idea: temporarily add a TDBGrid on the form, link it to the same TDataSource of the TLookupComboBox and check that you actually see the wanted data populate it. In fact it's easy to typo something in a query (assuming you are using a SQL DataSet) and get no data and then you are left wondering why the TDBLookupComboBox won't fill in.
Once seen the data correctly show up, remove the grid.
Another sensible idea is to use ClientDataSets for these kinds of implementations: due to how they work, they will "cache" the few rows contained in your look ups at program startup and then no further database access (and slowdown and traffic) will be required.
Now open the TDBLookupComboBox properties and fill in only the following ones:
ListSource (and not DataSource): set it to the TDataSource connected to the DataSet you want to show values of.
ListField: set it to the field name that you want the user to see. In our demo's case it'd be the value field.
KeyField: set it to the field name whose value you want the program to return you. In our demo it'd be the id field.
Don't forget to check the TabOrder property, there are still people who love navigating through the controls by pressing the TAB key and nothing is more annoying than seeing the selection hopping around randomly as your ComboBox was placed last on the form despite graphically showing second!
If all you need is to show a form and read the TDBLookupComboBox selected value when the user presses a button, you are pretty much sorted.
All you'll have to do in the button's OnClick event handler will be to read the combo box value with this code:
SelectedId := MyCombo.KeyValue;
Where SelectedId is any variable where to store the returned value and MyCombo of course is the name of your TDBLookupComboBox. Notice how KeyValue will not contain the text the user sees onscreen but the value of the id field we specified in KeyField. So, if our user selected database row was:
id= 5
value= 'MyText'
MyCombo.KeyValue shall contain 5.
But what if you need to dynamically update stuff on the form, depending un the combo box user selection? There's no OnChange event available for our TDBLookupComboBox! Therefore, if you need to dynamically update stuff around basing on the combo box choices, you apparently cannot. You may try the various "OnExit" etc. events but all of them have serious drawbacks or side effects.
One possible solution is to create a new component inheriting from TDBLookupComboBox whose only task is to make public the hidden OnChange event. But that's overkill, isn't it?
There's another way: go to the DataSet your TDBLookupComboBox is tied to (through a DataSource). Open its events and double click on its OnAfterScroll event.
In there you may simulate an OnChange event pretty well.
For the sake of demonstration, add one integer variable and a TEdit box to the form and call them: SelectedId and EditValue.
procedure TMyForm.MyDataSetAfterScroll(DataSet: TDataSet);
var
SelectedId : integer;
begin
SelectedId := MyDataSet.FieldByName('id').AsInteger;
EditValue.Text := MyDataSet.FieldByName('value').AsString;
end;
That's it: you may replace those two demo lines with your own procedure calls and whatever else you might need to dynamically update your form basing on the user's choices in your combo box.
A little warning: using the DataSet OnAfterScroll has one drawback as well: the event is called more often than you'd think. In example, it may be called when the dataset is opened but also be called more than once during records navigation. Therefore your code must deal with being called more frequently than needed.
At this point you might rub your hands and think your job is done!
Not at all! Just create a short demo application implementing all the above and you'll notice it lacks of an important finishing touch: when it starts, the combo box has an annoying "blank" default choice. That is, even if your database holds say 4 choices, the form with show an empty combo box selected value at first.
How to make one of your choices automatically appear "pre-selected" in the combo box as you and your users expect to?
Simple!
Just assign a value to the KeyValue property we already described above.
That is, on the OnFormCreate or other suitable event, just hard-code a choice like in example:
MyCombo.KeyValue := DefaultId;
For example, by using the sample database row posted above, you'd write:
MyCombo.KeyValue := 5;
and the combo box will display: "MyText" as pre-selected option when the user opens its form.
Of course you may prefer more elegant and involved ways to set a default key than hard-coding its default value. In example you might want to show the first alphabetically ordered textual description contained in your database table or whatever other criterium. But the basic mechanic is the one shown above: obtain the key / id value in any manner you want and then assign it to the KeyValue property.
Thank your for reading this HowTo till the end!

How to bind combination of db fields to single property (C#, WinForms, LINQ to SQL)?

I want to bind single control attribute (TextBox.Text) to combination of database fields using Linq to SQL (in C#/WinForms project).
For example:
1) I have a table Customer with columns CustomerName, CustomerCity and IsBigCustomer (boolean)
2) On a WinForm I have a TextBox "cInfo" and a ListBox "cList"
3) I have binded "cList" to CustomerName column (when I change item in cList, I need the appropriate Customer data presented in cInfo.Text)
4) I want to bind "cInfo" TextBox.Text property to combination of database columns - for example i would like to show:
a) "!"+CustomerName+": "+CustomerCity (if Customer's IsBigCustomer=true)
b) CustomerName+": "+CustomerCity (if Customer's IsBigClient=false)
And when a user changes cInfo.Text I need it to be validated and changes sent back to database (if validation is successful)
Sample data:
{IBM, New York, true} => cInfo.Text should be "!IBM: New York"
(SmallCustomer, Paris, false) => cInfo.Text should be "SmallCustomer: Paris"
How can I accomplish this task?
(The question is not about usefulness of such an aproach, but to understand if it is possible to bind more than one db field to one property and how to do it)
How about the validation of the data. If you have it in a text field they can put anything, how about if someone puts in "Some!Big:Company:Bad:!Data" What would that do for you...
I can only suggest that on your form, you have something like..
Checkbox for "Big Client"
Textbox for the Name
Textbox for the City
then, pushing the data back to the server is much easier too.

Update data in ComboBox while form is still open

I have form in which I can change the name of stations in my database (SQL Server: in table Stations).
To choose which station I want to edit I've used a combobox.
What I want to happen now is that when I update a station, my ComboBox with stations immediatly gets updated with the edited station.
Is there a way to do this or is this impossible?
I am assuming that this is a Windows Forms application based on the subject. If this is the case, then you have most likely performed databinding, perhaps using a DataTable or a collection, to the ComboBox.
If this is the case, and the object that you have databound supports System.ComponentModel.IBindingList, then all you need to do is add or update the record in the underlying object.
When this happens, the object that has implemented IBindingList sends a message out to any controls that are "listening" and tells them what just happened. The control will then update their data/user interface to reflect these changes.

Silverlight autocomplete textbox control?

Is there a control in Silverlight which act like the TO text box in email composers
which when you start typing it gives you a list of contacts and when select one and start type again will give you the contact list to select another email address (multi email addresses selection)?
You want the AutoCompleteBox
You set up an ItemsSource to be the possible e-mail addresses and when the user starts typing it will search against this list and suggest matches. So in your scenario you'd need to read the address book to populate this list.
You don't have to bind to a list of strings, it allows you to bind to an object and display and match against the human readable representation of that object.

Bind objects of different types to combobox in WPF

Requirement:
1. Show a list of all referral types in a combo box. (eg. Newspaper, Yellow Pages, Client)
2. Upon choosing client, a popup is shown where they can search for clients within the system.
3. From the popup, the user can choose one client.
4. Popup will be dismissed and the client name will be populated into the combobox.
I'm almost done with the implementation, wherein requirements 1 thru 3 are done. However, I'm stuck with number 4. The reason is that, the combobox is bound to referraltype objects. However, the chosen item from the popup is of type "client". Right now, I'm just displaying the chosen client in a separate textblock. However, the customer wants it to be displayed as part of the combobox itself.
Not sure how it could be done.
Any help would be appreciated.
Thanks
Bala
You could have a BaseReferralTypeViewModel which NewspaperViewModel, YellowPagesViewModel and ClientViewModel all inherit from. In the combo box resources in xaml declare DataTemplates which describe how to display these types in the combo box. In the case of the first two types its probably just a text block.
In the case of the ClientViewModel create an instance but don't initialise it with any client data.
The DataTemplate can detect this and just display the referral type.
Once the ClientViewModel is initialised with client data by the popup the DataTemplate will detect this and display the name.

Resources