The AutoCompleteSource and AutoCompleteMode properties of the TextBox allow me to use automatic completion in textboxes.
I have bound directly a datatable as AutoCompleteSource of the textbox and it works well.
In some situations that the input words is not available in the sources, the auto completion has no result and so, i need to do something else in those situations.
How should i check whether the automatic completion result is empty?
Here is one approach you can take. The following code will get suggestions in the TextChanged event of the textbox when more than 3 characters have been entered. We go get the suggestions and then check if any suggestions were returned. If yes, we set the AutoCompleteCustomSource. Otherwise, we will do something--whatever we want to do.
private void textBox1_TextChanged(object sender, EventArgs e)
{
TextBox t = sender as TextBox;
if (t != null)
{
// Here I am making the assumption we will get suggestions after
// 3 characters are entered
if (t.Text.Length >= 3)
{
// This will get the suggestions from some place like db,
// table etc.
string[] arr = GetSuggestions(t.Text);
if (arr.Length == 0) {// do whatever you want to}
else
{
var collection = new AutoCompleteStringCollection();
collection.AddRange(arr);
this.textBox1.AutoCompleteCustomSource = collection;
}
}
}
}
Related
I want to create a table in C#. The table contains two column headers. One column header is the products and the other column header is the price of the products.
I want to enter the data by clicking on a cell in the table. I want to enter only numbers in the cells of the products price column.
Does anyone know how to allow only numbers in the cell below the product price?
Picture of the table
My ideas:
My idea is that if I enter a string in the cell of the product price column, I should use "replace" to make the cell empty. Maybe regex could be used, although I don't know how. Another idea I have is that after I leave the cell, if there is a string in the cell, I have to empty the cell. But unfortunately I don't know how to implement my ideas. I don't know how to tackle the task.
I want to do my task using "Windows Forms App (.Net Framework)".
An often overlooked issue with going to all the trouble of allowing only numeric characters to be typed into a cell is… that the user can still “copy/paste” offending text into a cell. So technically, even if we allow only numeric values to be typed… this does NOT release us from having to validate that the text is a valid number when the user leaves the cell.
Therefore, since we have to validate the text anyway, then, wiring up the grids CellValidating event is made for this. When this event fires we know the user is trying to “leave” the cell, therefore, before the user leaves the cell, we need to check that the text is a valid number. Otherwise, the grid’s DataError will continue complaining until the offending text is fixed.
Given this, then you have a choice. If you do not care what values the user types into the cell and are only concerned when the user “leaves” the cell, then all you need to do is wire up the grids CellValidating event. If you want to “help” the user by allowing only numeric values to be typed into a cell then more work is needed.
In addition, If we wire up the grid’s CellValidating event, then, we can catch bad data before it gets passed down to the underlying data source. However, the question is… “What do we do when this happens?” We MUST do something; we cannot let this go without the grids DataError complaining.
There are several ways you can approach this and the approach I use below works such that if the text is not valid, then a message box is displayed stating the text in the cell is invalid. In addition, the offending cell is colored a light red to help the user see which cell is the offending cell. When the user presses the “OK” button on the dialog, the offending text is replaced with the previous value. Basically, the same thing the user would experience when pressing the Esc key minus our message box prompt to warn the user.
It is your call how you handle this, IMO, warn the user, then go back to the old value, then move on. This way the user isn’t continuously bugged until they fix the offending text, however, in some cases this may not be the desired behavior.
So, in this example we want to help the user and only allow numeric values to be entered into a cell AND when the user leaves the cell, we want to make sure that the typed/or pasted text is valid. The last part we discussed above… and we will use the grids Cellvaidating event specifically for when the user leaves the cell.
Big Picture…
From a big picture perspective, is what we will be doing below goes something like this: first we will wire-up the grids EditingControlShowing event. This event is the first step and it will allow the code to examine “which” cell is being edited. If the edited cell is one of the numeric cells, then we will simply cast that cell to a global TextBox variable named CurrentCellBeingEdited and then wire up that text boxes KeyPress event. Then we simply wait for the user to type characters.
When the user does indeed type something, then the text boxes KeyPress event will fire. In that event, we will simply check to see if the character is a valid numeric character. If the character is NOT a valid numeric character, then we will “ignore” that character and continue.
Finally, when the user leaves the cell, this will fire the grids CellValidating event where we will check for a valid numeric value. Obviously as already noted, we need this event just in case the user “copy/pasted” some offending text into the cell.
Below is a small example of what is described above. In the example, the grid has four (4) columns: Description, Cost, Quantity and Total. Description is a simple string cell and can have alpha characters and numbers. The Cost cell is a decimal value and we will allow only numeric values and a single decimal place. The Quantity column will be an int value where only numeric values are allowed. Finally a Totals column that is an expression column in the underlying DataTable that calculates the Cost times Quantity. Note the Totals column is not editable by the user.
Create a new winforms solution and drop a DataGridView onto the form and follow along below. The finished product should look something like…
To start, I made one global TextBox variable called CurrentCellBeingEdited. This variable will be set to the currently edited cell. This is used for convenience and is not really necessary, however for this example, it makes things a little clearer.
TextBox CurrentCellBeingEdited = null;
We will assign this variable to the cell the user typed into IF the cell is one of the numeric valued cells. Then we will subscribe (wire-up) the TextBox’s KeyPress event to the proper KeyPress event. This is all done in the grids EditingControlShowing event and may look something like…
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
if (CurrentCellBeingEdited != null) {
CurrentCellBeingEdited.KeyPress -= new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
CurrentCellBeingEdited.KeyPress -= new KeyPressEventHandler(NumbersOnlyCell_KeyPress);
}
string targetCellColName = dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name;
if (targetCellColName == "Cost" || targetCellColName == "Qty") {
CurrentCellBeingEdited = (TextBox)e.Control;
if (targetCellColName == "Cost") {
CurrentCellBeingEdited.KeyPress += new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
}
else {
// Qty cell
CurrentCellBeingEdited.KeyPress += new KeyPressEventHandler(NumbersOnlyCell_KeyPress);
}
}
}
This event simply wires up the TextBox cell to the proper key press event if needed. The first if statement…
if (CurrentCellBeingEdited != null) {
CurrentCellBeingEdited.KeyPress -= new KeyPressEventHandler(DecimalNumbersOnlyCell_KeyPress);
CurrentCellBeingEdited.KeyPress -= new KeyPressEventHandler(NumbersOnlyCell_KeyPress);
}
is used to unsubscribe (un-wire) any previously subscribed to event. This prevents the event from firing in the wrong cells. Example; if the user selects the Description cell. And the same idea applies to the Quantity cell where we do not want the user to type a period for a decimal place. The main point is that if we do not “unsubscribe” the text box from the event, then it may get fired multiple times and possibly for the wrong cells.
After any previously enabled event is un-subscribed, the code simply checks which cell is being edited. If the edited cell is a Cost or Quantity column, then the code casts our global variable CurrentCellBeingEdited to the edited cell, then subscribes to the appropriate event.
Next we will need the two KeyPress events for the Cost and Quantity cells and they may look something like…
// Quantity cell
private void NumbersOnlyCell_KeyPress(object sender, KeyPressEventArgs e) {
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar)) {
e.Handled = true;
}
}
// Cost cell
private void DecimalNumbersOnlyCell_KeyPress(object sender, KeyPressEventArgs e) {
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.') {
e.Handled = true;
}
if (e.KeyChar == '.' && (sender as TextBox).Text.IndexOf('.') > -1) {
e.Handled = true;
}
}
And finally, the grids CellValidating event. Note, the code allows cells to be “empty.” The code checks to see if the cell is a Cost or Quantity column, then applies a TryParse to the appropriate cell to validate if the text in the cell is indeed a valid int or decimal value. If the TryParse fails, then the cell is colored red and a message box is displayed indicating the invalid text. After the user clicks the OK button on the message box, the edit is canceled.
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
if (CurrentCellBeingEdited != null) {
string targetCellColName = dataGridView1.Columns[e.ColumnIndex].Name;
if (targetCellColName == "Cost" || targetCellColName == "Qty") {
if (!string.IsNullOrEmpty(CurrentCellBeingEdited.Text)) { // <- Allow empty cells
bool valid = true;
if (targetCellColName == "Cost") {
if (!decimal.TryParse(CurrentCellBeingEdited.Text, out decimal value)) {
valid = false;
}
}
if (targetCellColName == "Qty") {
if (!int.TryParse(CurrentCellBeingEdited.Text, out int value2)) {
valid = false;
}
}
if (!valid) {
CurrentCellBeingEdited.BackColor = Color.LightCoral;
MessageBox.Show("Invalid input - value will revert to previous amount");
dataGridView1.CancelEdit();
CurrentCellBeingEdited.BackColor = Color.White;
}
}
}
}
}
Putting all this together and to complete the example, the code below uses the events above to demonstrate this functionality.
TextBox CurrentCellBeingEdited = null;
public Form1() {
InitializeComponent();
dataGridView1.CellValidating += new DataGridViewCellValidatingEventHandler(dataGridView1_CellValidating);
dataGridView1.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing);
}
private void Form1_Load(object sender, EventArgs e) {
DataTable GridTable = GetDT();
GetData(GridTable);
dataGridView1.DataSource = GridTable;
}
private DataTable GetDT() {
DataTable dt = new DataTable();
dt.Columns.Add("Description", typeof(string));
dt.Columns.Add("Cost", typeof(decimal));
dt.Columns.Add("Qty", typeof(int));
dt.Columns.Add("Total", typeof(decimal), "Cost * Qty");
return dt;
}
private void GetData(DataTable dt) {
dt.Rows.Add("Product1", 12.49, 2);
dt.Rows.Add("Product3", 2.33, 3);
dt.Rows.Add("Product16", 5.00, 12);
}
I hope this makes sense and helps.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Btn_FillDataGridView_Click(object sender, EventArgs e)
{
var source = new BindingSource();
List<Product> list = new List<Product> { new Product("Shoes",50.14), new Product("T-Shirt", 20.55) };
source.DataSource = list;
DtGrdV_Products.DataSource = source;
}
}
public class Product
{
private string _name;
private double _price;
[DisplayName("Product")]
public string Name { get => _name; set => _name = value; }
[DisplayName("Price of product")]
public double Price { get => _price; set => _price = value; }
public Product(string name, double price)
{
Name = name;
Price = price;
}
}
I am making a very simple program. Need some help clearing out a textbox after performing a search. I have used the cboPrograms.Text = string.Empty; but I must not be putting it in the right place. After I choose an option it will not clear.
private void cboPrograms_SelectedIndexChanged(object sender, EventArgs e)
{
if (cboPrograms.Text == "MFValidation")
{
System.Diagnostics.Process.Start("C:\\Program Files (x86)\\Mozilla\\Mozilla.exe");
}
else if (cboPrograms.Text == "Add/Remove Programs")
{
System.Diagnostics.Process.Start("C:\\Program Files\\AddRemove\\addremove.exe");
cboPrograms.Text = string.Empty;
}
{
cboPrograms.Text = string.Empty;
}
}
That's because cboPrograms is not a TextBox but a ComboBox. (Text boxes do not have a SelectedIndexChanged event.)
To clear a combo box you do this:
cboPrograms.SelectedIdex = -1;
Also, reading the text of the combo box is not a good practice. You should have a collection of objects bound to the combo box. Get the selected object by calling SelectedItem and then working with the object's properties. The text you're seeing should just be a textual representation of the object. See here for more info.
You are missing an else statement before this code
{
cboPrograms.Text = string.Empty;
}
Simple problem: I am checking to see if a combobox has had an item selected with string.IsNullOrEmpty(). Problem is, even if is is selected, the error message appears. What am I doing wrong?
Here is my code:
private void button1Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(comboBox1.SelectedText))//here should skip to else - but doesn't
{
MessageBox.Show("You must select a conversion type", "Error");
}
else
{
if (comboBox1.SelectedText == "Currency")
{
double input = Convert.ToDouble(textBox1.Text);
if (!string.IsNullOrEmpty(comboBox2.SelectedText))
{
string type = comboBox2.SelectedText;
double result = convertCurrency(type, input);
if (result != -1)
{
label1.Text = Convert.ToString(result);
}
}
else
{
MessageBox.Show("You must select a conversion type", "Error");
}
}
else
{
MessageBox.Show("curency");
}
}
}
Note: This is my second ever C# program - so please don't yell at me if I'm being stupid.
Generally a few observations/suggestions.
First you're using string values and are basing logic on these values, you might want to look into using an Enum and binding all it's values to the combo box. Then use the SelectedItem property and compare it to the Enum.
When nothing is selected the SelectedItem will return NULL, another option is using SelectedIndex which will return -1 when no item has been selected.
So with the SelectedIndex it would become something like;
if (comboBox1.SelectedIndex == -1)//Nothing selected
{
MessageBox.Show("You must select a conversion type", "Error");
}
else
{
//Do Magic
}
Generally using string comparisons should only be done when anything "strong" like an int comparison or even better an enum comparison is not possible. (Maybe it's just me though but strings change to often and are just scary for this sort of stuff.)
For the enum suggestion possibly look at one of these links;
Binding an enum to a WinForms combo box, and then setting it
Load values of enum type into a combobox
Is it possible to load items from an Enum to a ComboBox in .NET 3.5?
Binding a ComboBox to an Enumeration
I'm not sure which .NET version and things you're using as binding is alot easier in WPF then in the old windows form (in my opinion).
from the MSDN doc, this answers your question exactly
You can use the SelectedText property to retrieve or change the
currently selected text in a ComboBox control. However, you should be
aware that the selection can change automatically because of user
interaction. For example, if you retrieve the SelectedText value in a
button Click event handler, the value will be an empty string. This is
because the selection is automatically cleared when the input focus
moves from the combo box to the button.
private void button2_Click(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex==-1)
{
MessageBox.Show("You must select a conversion type", "Error");
}
else
{
MessageBox.Show("Selected");
}
}
Another solution:
You can check whether the combobox has had an item selected by checking a condition with an Index which is out of range (which item is impossible to have), then, if it is not having a possible value, you can set it manually.
if (comboBox1.SelectedIndex == -1) //index out of range
{
//show the error message
comboBox1.SelectedIndex = 1; //set the first value to the combo box
}
else
{
//continue
}
Poor naming on microsoft's part. You should use comboBox.Text to get what you are looking for.
comboBox.SelectedIndex the index of the selected value
comboBox.SelectedItem if you using a DataSource, this is the item seleted in the datasource
comboBox.SelectedValuethe ValueMember of the Datasource or the currently selected value if you added your own Items
comboBox.Text The text that you see, even if it is not in the list
.SelectedText, refers to and text selected (highlighted) within the .Text
private void Resetbtn_Click(object sender, EventArgs e)
{
comboBox1.Items.Clear();
//Student is a combobox elements.Add again.
comboBox1.Items.Add("Student");
comboBox1.Items.Add("Staff");
}
Hello guys I have a sample gridview
Here's what i want to happen.
When I open the form i load top 100 of data from the server in to the gridview. When I scroll down and reach the end of the scroll bar I want to load another data from 101 - 200.
so the data in the gridview is 1 to 200.
How do I determine if the scroll bar reach the end?
Depending on the version of XtraGrid you are using - perhaps you should check out InstantFeedback
It's a datasource that dynamicly get rows, when they come into view.
The great thing about this is - that it's a standard DevExpress component - so you don't have to invent anything youself.
OR:
You could force that behavior with some thing like this:
private bool _working = false;
private void view_RowStyle(object sender, RowStyleEventArgs e)
{
if(_working) return;
var view = sender as GridView;
if (view != null)
{
int lastRowIndex = (view.GridControl.DataSource as BindingSource).Count;
if (view.IsRowVisible(lastRowIndex) == RowVisibleState.Visible)
{
_working = true;
//go get more rows.
_working = false;
}
}
}
This assumes that you are using a BindingSource (if not, the you must change the cast type).
I handle the RowStyle event because the code in this event are executed "all time time".
You cah handle the scrolling to end (and any another conditions) via handling the Scroll event of GridControl's embedded scrollbar.
Here is the approach details:
var sb = GetScrollBar(gridControl1, ScrollBarType.Vertical);
sb.Scroll += new ScrollEventHandler(sb_Scroll);
//...
void sb_Scroll(object sender, ScrollEventArgs e) {
var scrollBar = sender as DevExpress.XtraEditors.ScrollBarBase;
if(e.NewValue == (scrollBar.Maximum - scrollBar.LargeChange)) {
MessageBox.Show("Last row is reached!");
}
}
ScrollBarBase GetScrollBar(GridControl gridControl, ScrollBarType type) {
foreach(Control c in gridControl.Controls) {
var scrollBar = c as ScrollBarBase;
if(scrollBar != null && scrollBar.ScrollBarType == type)
return scrollBar;
}
return null;
}
You can get the displayed rows count and calculate based on the total loaded rows and check in the TopRowChanged event and see if you need to load any more rows.
This is a more manually approach for this situation.
Also you can use the grid in server mode which does this for you.
Regards,
Mishu
I have a database with link urls and their respective display texts. I need to check if they are broken or not before their display string is shown in the gridview.
I am using SqlDatasource, is there a way to process records and use custom HTML markup to show them while using the SqlDataSource?
I am trying to use the OnSelected event of SqlDatasource but cant get how to use it.
I believe what you are trying to do is make sure that the hyperlink is valid before it gets put into the datagrid. To do this, you would need to subscribe to the RowDataBound event on your grid. From there, you can run code to evaluate your URL. Here is a quick example that would check to be sure that the URL field is not an empty string:
protected void selectedBookList_RowDataBound(object sender, GridViewRowEventArgs e)
{
if ((e.Row != null) && (e.Row.RowType == DataControlRowType.DataRow))
{
string test = DataBinder.Eval(e.Row.DataItem, "URL").ToString();
if (test.Length == 0)
{
e.Row.Cells[3].Visible = false;
}
else
{
e.Row.Cells[3].Visible = true;
}
}
}
Instead of testing to be sure the length is equal to zero, you could check to see if the link is dead or not. Once you have evaluated it, you can hide the cell like I am doing here or you could modify the link, put in a generic link, etc.