I have a DataGridView, and I would like to have something similar to a MaskedTextBox inside my DataGridView. It doesn't have to be an exact MaskedTextBox, but at least somewhat acting like one.
Here is what my DataGridView looks like.
All I want is that the people who modify the DataGridView's right column (Durée - 'Duration'), follow the Mask pattern 00:00:00 for time.
Another solution would be to place a DateTimePicker. But similar to the solution using a MaskedTextBox, it does supposedly not exist as DataGridView columns.
I have tried using the Column's Builder to add a Behavior→Format, but I don't think this is quite the same. I need something to prevent the user from adding random stuff.
You have (at least) two options:
You can use a regular MaskedTextBox overlaid over the TextBox the DGV creates for editing
You can code the regular edit control, i.e. the TextBox the DGV shows when entering edit mode.
Here are examples for both:
First we create class level variables for the controls:
TextBox editBox = new TextBox();
MaskedTextBox editMBox = new MaskedTextBox();
To get a reference to the editing textbox we code the EditingControlShowing event:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
editBox = e.Control as TextBox;
}
To control user input we hook up the KeyPress event:
public Form1()
{
InitializeComponent();
..
editBox.KeyPress += editBox_KeyPress;
..
}
Here we can do all sorts of check and prevent bad characters from entering. All the regular properties are there..:
void editBox_KeyPress(object sender, KeyPressEventArgs e)
{
string sNew = editBox.Text.Substring(0, editBox.SelectionStart)
+ e.KeyChar + editBox.Text.Substring(editBox.SelectionStart);
Console.WriteLine(sNew);
e.Handled = !validateMethod(sNew);
}
This would call a function you can write..
But if you are happy with what a MaskedTextBox you can simply use one:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
DataGridViewCell cell = dataGridView1.CurrentCell;
editMBox.Parent = dataGridView1;
editMBox.Location = dataGridView1.GetCellDisplayRectangle(cell.ColumnIndex,
cell.RowIndex, false).Location;
editMBox.Size = editBox.Size;
editMBox.Show();
editMBox.Mask = yourMask;
editMBox.BringToFront();
}
We need to hook up the KeyPress event for the MaskedTextBox to end to editing. Here is just a simple way to accept the value when Enter is pressed.
You will want to handle Esc here and also at least the CurrentCellChanged event for more complete control..
void editMBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
editBox.Text = editMBox.Text;
editMBox.Hide();
}
}
I found this neat little program MaskedTextBoxColumn in DataGridViews. I had found that a little earlier, but was reluctant to download it since we had to register and stuff. Actually worked out pretty well. The mask properties is a little too simple, as it is lacking some nice features, but the general MaskedTextBox idea is there.
Related
I need to make it so when the user clicks on a cell with TextEdit in a grid view, it will select all in the textedit. I tried many many ways i could find in the internet, but none of them work well.
"EditorShowMode = MouseUp" way breaks everything, for example when you click on a cell that has checkedit; it selects the cell, then you need o click again to actually click on the CheckEdit.
"Use EditorShowMode = MouseUp and manually handle other things on MouseDown" is just ew. Won't work fine for all types of controls.
"Change selection length etc. on ShownEditor event" way doesn't work too, actually it selects the text when clicked, but it doesn't override the default function so the selection instantly changes. Also tried the SelectAll method but it had some problems that i dont remember (probably didnt work at all).
I have really tried many things, but couldn't find a totally fine way. Please tell me if you can get a working way without breaking other types of controls in the grid.
Answered by Pavel on DevExpress Support (works great):
The easiest way to achieve this is to use the GridView.ShownEditor event to subscribe to the active editor's MouseUp event. Then, select all text in the MouseUp event handler and detach this handler to avoid subsequent text selection.
private void GridView_ShownEditor(object sender, EventArgs e)
{
GridView view = sender as GridView;
if (view.ActiveEditor is TextEdit)
view.ActiveEditor.MouseUp += ActiveEditor_MouseUp;
}
private void ActiveEditor_MouseUp(object sender, MouseEventArgs e)
{
BaseEdit edit = sender as BaseEdit;
edit.MouseUp -= ActiveEditor_MouseUp;
edit.SelectAll();
}
You could use GridView CustomRowCellEdit event and set an event of text editor such as Mouse Up. Setting the RepositoryItemTextEdit MouseUp event can be set as in the example.
Example:
private void gridView1_CustomRowCellEdit(object sender, CustomRowCellEditEventArgs e)
{
if (e.RepositoryItem is DevExpress.XtraEditors.Repository.RepositoryItemTextEdit)
{
DevExpress.XtraEditors.Repository.RepositoryItemTextEdit rep = new DevExpress.XtraEditors.Repository.RepositoryItemTextEdit();
rep.ReadOnly = false;
rep.MouseUp += rep_MouseUp;
e.RepositoryItem = rep;
}
}
void rep_MouseUp(object sender, MouseEventArgs e)
{
DevExpress.XtraEditors.TextEdit te = sender as DevExpress.XtraEditors.TextEdit;
te.SelectAll();
}
You should handle Enter event for TextEdit
private void myRepositoryItemTextEdit_Enter(object sender, EventArgs e)
{
var editor = (DevExpress.XtraEditors.TextEdit)sender;
BeginInvoke(new MethodInvoker(() =>
{
editor.SelectionStart = 0;
editor.SelectionLength = editor.Text.Length;
}
}
I'm making a settings form, where user can assign custom hotkeys for the application. There's a TextBox, and by clicking it with mouse, it focuses and waits for one keypress and then defocuses (by focusing another label):
private void txtKey_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = true;
}
private void txtKey_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
TextBox textBox = (TextBox)sender;
textBox.Text = e.KeyCode.ToString();
label1.Focus();
}
Is there a way to defocus focused TextBox (and cancel the key assinging process), by either clicking it again with mouse, or by clicking the GroupBox around it? I can't figure out how to check if TextBox was already focused when clicked (because when clicked, it gets focused before I can test if it's focused). Of course I can add a button "Cancel" next to the TextBox, but that's not what I want.
There is no Click-event for GroupBox, so I can't defocus TextBox by clicking GroupBox around it. Or can I somehow?
You can set/remove the Focus with
Keyboard.Focus = null;
You can also register to the following event:
public event MouseButtonEventHandler PreviewMouseLeftButtonDown
This event fires every time you click on the TextBox, thus you can set the Focus there if you want to.
For Winforms there is a way as well. I'm not proficient in it, but here would be a way:
Make a textBox (e.g. named textBoxFocus) that lies outside your window. Size it 1, 1 and move it to -10,-10 for example. Then you can register to the Click event and write
textBoxFocus.Focus();
It's a bit of a roundabout way, but should achieve what you want.
Thanks to private_meta for getting me to right direction (in comments)! I set the flag with click event, and before setting the flag, testing if flag is set. So first click does not find the flag, but second will. And flag is cleared within textbox Enter-event (which fires before Click-event). Now every other click focuses and every other defocuses textbox, as I wanted.
private void txtKey_Enter(object sender, EventArgs e)
{
TextBox textBox = (TextBox)sender;
textBox.Tag = null;
}
private void txtKey_Click(object sender, EventArgs e)
{
TextBox textBox = (TextBox)sender;
if (textBox.Tag != null) label1.Focus();
textBox.Tag = "clicked";
}
One of the simple way is that, you may use a bool flag here.
Algorithm:
By default, the bool value is 0;
If(Textbox Selected && flag = 0)
Do your task; and flag = 1;
I hope I could satisfy your query and you can follow this algorithm.
is there a way to allow editing a string partially in c# and wpf textbox?
somthing , if the contents of the TextBox were for example
"http://xxxx.xxx/xx/path?param1=xxx¶m2=xxx"
the x can be replaced with whatever length but any thing else is constant and cannot be edited in the textbox, any way to achive such thing?
There are two relevant events that you can handle on the TextBox; the PreviewKeyDown and the PreviewTextInput events. By handling these two events, you will have complete control over what the user can and can't edit in the TextBox. Of course you will need to work out the logic inside, but the event handlers are the tool to enable you to do what you want:
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
// Do your text filtering here using e.Key and e.Handled
}
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
// Do your text filtering here using e.Text and e.Handled
}
I have a Winforms app written in C#.
In one of my DataGridViews I have set all columns except one called 'Reference' to ReadOnly = true;
I want the application to know when a User has changed anything in the 'Reference' column, but all the events I have tried so far fire a lot more than when a user has made changes. For example CurrentCellChanged fires when the DataGridView is initially rendered and everytime the user simply clicks or tabs along the rows etc.
I'm only interested in catching user changes to data in the 'Reference' column which is the ONLY column where ReadOnly = false;
Which is the best event to use for this?
CellValueChanged is what you need:
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e){
if(dataGridView1.Columns[e.ColumnIndex].Name == "Reference"){
//your code goes here
}
}
I think the event CellEndEdit is also suitable for your want:
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e){
if(dataGridView1.Columns[e.ColumnIndex].Name == "Reference"){
//your code goes here
}
}
In my case CellValueChanged event was also triggering while the DGV was initializing, so I wanted to use CellEndEdit, as King King mentioned in his answer.
To make King King's second answer more bullet-proof (see JPProgrammer's comment), i.e. only react, if a value was entered in the cell, you can do the following:
private void DataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
int? rowIdx = e?.RowIndex;
int? colIdx = e?.ColumnIndex;
if (rowIdx.HasValue && colIdx.HasValue)
{
var dgv = (DataGridView)sender;
var cell = dgv?.Rows?[rowIdx.Value]?.Cells?[colIdx.Value]?.Value;
if (!string.IsNullOrEmpty(cell?.ToString()))
{
// your code goes here
};
};
}
Notice the null handling by using ?. and ?[ operators. I have written it so that it can be used in a more general way, but of course you can add the check for the "Reference" column, just replace the inner if statement above by the following:
if (dgv.Columns[colIdx.Value].Name == "Reference")
{
if (!string.IsNullOrEmpty(cell?.ToString()))
{
// your code goes here
};
};
I would like to be able to set the CharacterCasing of a specified column to uppercase.
I can't find a solution anywhere that will convert characters to uppercase as they are typed.
Many thanks for any help
You need to use EditingControlShowing event of the Datagridview to edit the contents of any cell in a column. Using this event you can fire the keypress event in a particular cell. In the keypress event you can enforce a rule which will automatically convert lowercase letters to uppercase.
Here are the steps to achieve this:
In the EditingControlShowing event see whether user is in the column in which you want to enforce this rule. Say your column is 2nd column in the grid
private void TestDataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if(TestDataGridView.CurrentCell.ColumnIndex.Equals(1))
{
e.Control.KeyPress += Control_KeyPress; // Depending on your requirement you can register any key event for this.
}
}
private static void Control_KeyPress(object sender, KeyPressEventArgs e)
{
// Write your logic to convert the letter to uppercase
}
If you want to set the CharacterCasing property of the textbox control in the column, then you can do it where KeyPress event registering is done in the above code, which is in the 'if' block of checking column index. In this case you can avoid KeyPress event.
That can be done in the following way:
if(e.Control is TextBox)
{
((TextBox) (e.Control)).CharacterCasing = CharacterCasing.Upper;
}
Currently i really know, but if you could get access to the editing control of the column (which is a TextBox) you could probably set the CharacterCasing property.
Use EditingControlShowing event of the Datagridview to Edit the contents
After that Apply the Condition For Specific Column
private void dgvGrid_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dgvGrid.CurrentCell.ColumnIndex == 0 || dgvGrid.CurrentCell.ColumnIndex == 2)
{
if (e.Control is TextBox)
{
((TextBox)(e.Control)).CharacterCasing = CharacterCasing.Upper;
}
}
}
Happy Coding