I want to implement something like Google's search bar behavior for our application: user must be able to enter user name as free text and based on entered data system must provide a couple of suggestions on a popup bar based on already existent user names.
Here's the brief algorithm:
user enters some character to text edit box
system fires some changing event with web service call inside it that updates suggestions list data
Text edit must also provide an ability to enter and keep a free text to create new user, not just looking up for existent
I can't use devexpress's lookupeditds - they allow to keep only values, presented in datasource - even if new value has being processed inside ProcessNewValue by adding to datasource,
Changing event fires one more time with refreshing my datasource overwriting new unique value.
Now I am looking forward Combobox control. But looks like there is no ability to enter free text alongside with displaying suggestions popup.
I can't use devexpress's lookup edits - they allow to keep only values, presented in datasource - even if new value has being processed inside ProcessNewValue by adding to datasource,
I believe you're wrong here because you can use the DevExpress LookUpEdit with easy:
class AutoCompleteLookUpEdit : LookUpEdit {
List<string> suggestions = new List<string>();
public AutoCompleteLookUpEdit() {
Properties.DataSource = suggestions;
Properties.ImmediatePopup = true;
}
protected override void ProcessFindItem(KeyPressHelper helper, char pressedKey) {
suggestions.Clear();
// add search suggestions here depending on helper.Text value
suggestions.Add("google");
suggestions.Add("devexpress");
// ...
base.ProcessFindItem(helper, pressedKey);
}
}
Take a look at the How to create an editor with a dynamic autocomplete list for the detailed example.
P.S. You can use the AcceptEditorTextAsNewValue property to control whether or not lookup accepts entered text as valid value even it does not belong the underlying data source.
Related
I have a DataGridView with several TextBoxColumns and one ComboBox column called 'combo' that holds the client type. The problem is that I'd like to show both the currently selected client-type value along with the dropdown client-type list to validate future changes by the user. In SQL Server, I have a DB with two table columns, 'client_type_dropdown.name' and 'clients.client_type'. The 'client_type_dropdown.name' column is a validation list. The 'clients.client_type' column contains the current client type for clients in the database. Is there a way to show in 'combo' both 'client_type_dropdown.name' and 'clients.client_type' , i.e., one source for the ComboBoxColumn dropdown and a different source for the textbox part of 'combo'? Or do I need to have two columns in my grid?
I appreciate your help.
I'm using a third party grid, but I usually handle this by setting the combo drop down style to DropDown instead of DropDownList. This will allow your original database value to display, even if it isn't in the list.
This also allows free typing of values into the combo field, so the trick after that is to validate the user input to make sure it matches a value in the list before you allow them to save updated values. You could play around with the LimitToList property of the combo to possibly save you doing the validation manually, but with most controls I have worked with it will give you more grief than help.
Iam using AutoCompleteMode to my textbox. It will append the Bank names to my textbox. So when I started typing with the first leter all the Bank names with first lettre will come to dropdownlist to my textbox. Now my question is
If user try to entre the data which is not im my dropdownlist, the user should not able to entre the text. So i want user to entr the existing bank names only.
Iam using AutoCompleteCustomSource to the textbox for dropdown.
try something like:
bool foundSome = false;
foreach (var bankName in col)
{
foundSome = bankName.StartsWith(textBox.text);
}
if (foundSome)
//Do some action
You can write this code in 'Validating' to preform for each char inserted in txtbox.
the best way to achieve your requierement is to use 1 textbox and 1 combobox. They both should point to the same collection.
Textbox will behave in autocomplete mode as you described. Once you type, combobox value will be set to first matching value from your collection. If no value matches - combobox value should be set to null or default data.
Combobox will store only corresponding data subset with no possibility to edit the chosen text.
Validation and data retrieval will be done from Combobox value.
Advantages of this approach:
- With large sets of data it will be easier for user to find what he/she needs.
- Lesser code to check if input value belongs to data set or to force belonging.
- No validation is needed.
Possible shortcomings:
- One more control at form.
- Logic to synchronize textbox's text and combobox collection should be implemented.
I have written a GUI application that contains a DataGridView in which users can add new instances of an Arrow class by creating a new line in the view and filling in the new Arrow's properties. One of those properties is called transferType and is a string.
I allow users to set a list of valid transferTypes in a settings form. I am using Properties.Settings to save the settings, using the convent tool built into Visual Studio to create and manage application settings.
Rather than having the user enter the transferType field by hand and have the DataGridView reject the entry if it does not match any of the valid transferTypess, I have been trying to set up the column of the DataGridView to use drop down menus populated with the valid options. To do this, using Visual Studios GUI Design tool(which was used to build the GUI) I edited the column and changed the "Column Type" from DataGridViewTextBoxColumn to DataGridViewComboBoxColumn. That change allows me to select a DataSource to populate the selections of the combo box, so I went and under "Other data sources" attempt to select "Properties" which stores my settings (Properties.Settings.Default), but for some reason Visual Studio won't allow me to select it.
I then tried set the DataSource of the combo box in code after the initialization of the GUI, using the line" ((DataGridViewComboBoxColumn)arrowView.Columns[3]).DataSource = Properties.Settings.Default.validTransferTypes; (Transfer Type is the fourth column), but when I ran my program I get this error when I click on the combo box and try to "drop it down":
The following exception occured in the DataGridVIew:
System.ArgumentException: DataGridViewComboBoxCell value is not valid.
To replace this default dialog please handle to DataError event.
The error loops and reappears immediately after hitting OK or exiting the window.
I'm assuming that there has to be a reasonable way to use my settings to populate a combo box, but can't figure out how. I also don't understand why Visual Studio won't allow me to create a DataSource using Properties. Any help would be appreciated.
(This is also my first posted question, so be gentle with the criticism please :) )
UPDATE:
It turns out that using ((DataGridViewComboBoxColumn)arrowView.Columns[3]).DataSource = Properties.Settings.Default.validTransferTypes; does correctly populate the combo box, but any time the combo box is moused over, the previously mentioned error comes up.
If you are using Properties.Settings.validTransferTypes as a string then the value of that combobox would only be a single string value. Do you have more values in your settings that you'd like to populate the combobox with? It seems that the error is coming because you have nothing else for the combobox to read other that the single string you are loading in. Trying to load an array with Properties.Settings.Default may be an option and then setting the datasource equal to that array.
I have a VERY simple windows form that the user uses to manage "Stores".
Each store has a name and number, and is kept in a corresponding DB table.
The form has a listbox of stores, an add button that creates a new store, a delete button, and an edit button.
Beside those I have text boxes for the name and number, and save/cancel buttons.
When the user chooses a store from the list box, and clicks 'edit', the textboxes become populated and save/cancel become active. When the user clicks 'add', I create a new Store, add it to the listbox, activate the textboxes and save/cancel buttons, then commit it to the database when the user clicks 'save', or discards it when the user clicks 'cancel'.
Right now, my event system looks like this (in psuedo-code. It's just shorter that way.)
add->click:
store = new Store()
listbox.add(store)
populateAndEdit(store)
delete->click:
store = listbox.selectedItem
db.deleteOnSubmit(store)
listbox.remove(store)
db.submit()
edit->click:
populateAndEdit(listbox.selectedItem)
save->click:
parseAndSave(listbox.selectedItem)
db.submit()
disableTexts()
cancel->click:
disableTexts()
The problem is in how I determine if we are inserting a new Store, or updating an existing one.
The obvious solution to me would be to make it a "modal" process - that is, when I click edit, I go into edit mode, and the save button does things differently than if I were in add mode.
I know I could make this more MVC-like, but I don't really think this simple form merits the added complexity. I'm not very experienced with winforms, so I'm not sure if I even have the right idea for how to tackle this.
Is there a better way to do this? I would like to keep it simple, but usable.
use some type of identifier, i.e., the name of the store. Now, when the user presses Save, check to see if your collection of stores already contains one with the same name. If it does, it's an update, otherwise it is a new store.
I realize that using the name of the store may not be possible for you (i.e., a supermarket with many branches), but you get the idea.
Surely you have some kind of ID in the database? Your object would expose this primary key as a StoreID or ID property for example. If it's a GUID, it'll be Guid.Empty for a new object, if it's an auto-incrementing integer it would be zero. When you save it to the database, it should get a valid ID and then you can easily tell if the object is new or existing.
you could check some kind of unique identifier as previously mentioned, or in the framework my company uses (CSLA .NET) there is a boolean IsNew field on our objects, that when we create a new object the field is marked true. When data is read into the object from the database the IsNew field is marked as false. This gives you the ability to have some kind of use the default new constructor in all cases, then when you populate an existing item mark it false.
In your situation, you may want to look at storing more than just a simple string to the listbox. Do you have any domain objects which the listbox values represent? Add these to the listbox instead - make sure to override the .ToString() so that the listbox ends up visualizing something meaningful. When the user selects Add, create a new domain object and add it to the listbox, ensuring that the appropriate property is set to mark this as a new record for insert to the database. Conversely, any records persisted to the database, as well as all existing records fetched from the database, could be marked appropriately so that you can handle any necessary edits and deletes.
You can just play with the text of your save button, just in case if it's new store change its text to "Insert Store" and in case of edit it would be "Update Store".
add->click:
store = new Store()
listbox.add(store)
save.Text="Insert Store"
populateAndEdit(store)
delete->click:
store = listbox.selectedItem
db.deleteOnSubmit(store)
listbox.remove(store)
db.submit()
edit->click:
save.Text="Update Store"
populateAndEdit(listbox.selectedItem)
save->click:
parseAndSave(listbox.selectedItem)
if (save.Text.Equals("Insert Store"))
db.InsertOnSubmit(listbox.selectedItem)
db.submit()
disableTexts()
cancel->click:
disableTexts()
Hope this helps!
I am creating an invoice application and in the section where the user can enter line items, some of the fields will include: Quantity, Price, Extended Price, Description, etc.
If the user enters something into any of the fields, the corresponding fields are required, but if no data is entered into any field, then nothing is required in the corresponding fields. What is an efficient and clean way of doing this without doing a bunch of if statements?
I guess this is like doing validation if only one textbox has text.
You could try something like this in the ServerValidate event of a CustomValidator.
// test for all textboxes having some text in them...
e.IsValid = (from TextBox c in this.Controls
where c is TextBox
select c).All(tb => !string.IsNullOrEmpty(tb.Text));
That might need some tinkering to get right - but you get the idea. Change accordingly to test for all textboxes being blank.
You could also use jQuery for the client side validation in your CustomValidator
function clientValidate(sender, e) {
// get array of textboxes with a common css class
var textBoxes = $("#SomeCssSelector input").val();
// loop here to test for having text or no text.
e.IsValid = ... ;
}
You could create a TextBox array and store references to all related text boxes in the array. When ever you need to you could then iterate over the array in a for loop looking for the first item with a value. As soon as you find one with a value you know all the other items in that array also need values.
Additionally, if you have other groups of related text boxes you could create additional arrays to help keep them grouped.
Several ways if this is ASP.NET.
Use field validators that are available in ASP.NET.
Use JavaScript for Windows Forms.
For Windows Forms, also use control validators, or you could use a simple function where you pass a control array. If any item in the array is filled then it requires all items to be filled by returning which fields are not filled, etc.