I have a text box which has the following requirements:
Can be Empty
If not empty must be exactly 9 numbers
I would like it so as soon as you type a character into the textbox a message appears saying this is invalid and that message will remain visible without disappearing as long as the validation doesn't pass even while the user is typing into the box. For Example I type 1 into the box and immediately the error appears, then while I type 2345678 the message stays visible even when losing focus on the editor. Then as soon as I add 9 the message disappears. I already have working logic for the validation I just can't seem to get the events to fire how I want. For example if I start typing into the field the error disappears until it loses focus and then it reappears. How to I make it stay even while typing?
Html.DevExpress().TextBox(tb =>
{
tb.Name = "tbAddressChangeDUNS";
tb.Width = Unit.Percentage(100);
tb.Properties.ClientSideEvents.KeyUp = "function(s, e) {s.Validate();}";
tb.Properties.ClientSideEvents.LostFocus = "function(s, e) {s.Validate();}";
tb.Properties.ClientSideEvents.Validation = #"function(s, e) {
var duns = e.value;
if(!duns)
return;
if(!IsValidDunsNumber(duns)) {
e.isValid = false;
e.errorText = 'Must be exactly 9 digits';
}
}";
}).Render();
According to my comments, there is a big hint below that should solve your problem :
You can manually trigger validation at any moment via the ASPxClientEdit.Validate Method. Handle the [ASPxClientTextEdit.TextChanged][1] Event of the text box editor to execute custom logic (e.g., trigger validation) when its text is changed. I hope this information will help you.
source : https://www.devexpress.com/Support/Center/Question/Details/Q572171/how-to-implement-custom-validation-on-text-boxes
Related
I am trying to page up/down the contents of a simple textbox control in a simple Windows Form on NET 6.0, but something is wrong. Textbox shortcuts are enabled (probably why SendKeys.SendWait("^a"); works) and readonly is false.
I have a method (not on the UI thread) that I call to SendKeys.SendWait("{PgUp}"); to the foreground app (which is both the key sender and textbox (with focus) receiver.
If I type PgUp on the keyboard, the textbox pages up as expected.
If I SendKeys.SendWait("^a");, the textbox selects all text as expected.
If I Sendkeys.SendWait("{PgUp}");, the textbox adds a blank line to the bottom of the text.
From this I conclude that my code is working because it sends "^a" and the textbox receives it and selects all text. But somehow the textbox does not handle the "{PgUp}" key, even though it does when the PgUp key is sent by the keyboard.
I've read easily a dozen articles and posts on the web and SO that talk about paging using scrolling events, positioning the caret and then scrolling to the caret, and so on. But none of them say anything about why SendKeys(^a) and keyboard PgUp would work but SendKeys.SendWait("{PgUp}") would fail.
Can anyone tell me what I'm doing wrong and maybe what I need to do (or read) to fix it? Thank you
UPDATE: Jimi asked for some code, so here is the code that I use to send the ^a and the {PgUp} keys. I know this is not on the UI thread because it is executed from a voice-driven recognizer thread. The app is a voice-driven app that displays content in the textbox by textbox.AppendLines calls. I was trying to PgUp and PgDn the multi-line textbox by voice as well.
When I tried to use Send (I normally use .SendWait for everything in other programs), I received the following error message:
System.InvalidOperationException: 'SendKeys cannot run inside this
application because the application is not handling Windows messages.
Either change the application to handle messages, or use the
SendKeys.SendWait method.'
It is true that my app does not intercept Windows messages. I can't figure out why the app can receive and properly process my keyboard keys, and my "^a' shortcut keys, but not the SendWait("{PgUp}") key.
internal static void
HelperPageUp() {
var keys = "{PgUp}";
keys = "^a";
SendKeys.SendWait(keys);
}
I'm starting to think that {PgUp} is never handled by a textbox or control. Instead, probably {PgUp} must be handled by logic in a case statement that converts PgUp "orders" into sets of actions that implement whatever PgUp means to the app that receives the PgUp key. So maybe I will have to add a keystroke handler to the form. Maybe something like this:
textBox1_KeyUp(object sender, KeyEventArgs e) {
// identify the special key and implement what it means
if (e.KeyCode == Keys.PageDown) {
...
e.Handled = true;
}
Yes, my thought at the end of the question was correct. The ^a was handled by the textbox because I had textbox.EnableShortcuts=true;, so the textbox handled the popular ^a shortcut. But keys like {PgUp} are a different matter; they are not included in shortcuts.
The solution was to write code to handle the {PgUp} key explicitly in the form. Here is my code that worked.
void
textBox1_KeyUp(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.PageUp) {
// page the viewport up; watch for end of content
var charIndex = textBox1.SelectionStart;
var lineIndex = textBox1.GetLineFromCharIndex(charIndex);
// move 20 lines up, but not past zero
var newLine = lineIndex - 20;
var newIndex = Math.Max(0, newLine);
// set the new anchor and scroll to it
var newAnchor = textBox1.GetFirstCharIndexFromLine(newIndex);
textBox1.Select(newAnchor,0);
textBox1.ScrollToCaret();
e.Handled = true;
}
I am trying to set focus of a custom text box on validation error when they are placed next to each other. I have a made a CustomTextBox (Inherits from TextBox) in wpf.
I have to keep two customTextBox one after other in main xaml file.
What do I have to do?
Now on either moving tab or mouse click to outside any other other control or next placed CustomTextBox it must show validation error and should not loose focus if there is error in first one.
Where is the problem?
When I press a tab then it calls LostKeyboardFocus events 2 times. First time for the first CustomTextBox and then next time for the next placed CustomTextBox (I think pressing tab takes it there). I am triggering textbox bindings on LostKeyboardFocusof these custom textboxes and then I check for validation error which already works. And then I popup the error message which work as well
Problem is i have to keep the focus on first CustomTextBox on validation error whereas it is being called again by the next placed CustomTextBox.
My code here is (Only Relevant part):
public class CustomTextBox : TextBox
{
public CustomTextBox()
{
this.LostKeyboardFocus += CustomTextBox_LostKeyboardFocus;
}
private void CustomTextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
this.Text = updatedText;
BindingExpression be = this.GetBindingExpression(TextBox.TextProperty);
if (be == null)
{
return;
}
be.UpdateSource(); //triggers binding correctly
if (Validation.GetHasError(this))
{
e.Handled = true;
var errors = Validation.GetErrors(this);// gets validation error
MainLibrary.ShowErrors(errors[0].Exception); //Popups error window
Keyboard.Focus(this);
this.CaretIndex = this.Text.Length;
return;
}
}
}
How to make this CustomTextBox_LostKeyboardFocus not being called by secondly placed CustomTextBox when there is validation error?
When you show a new window, it will activate.
This means it takes focus.
Since only one thing can have focus, anything else you have will lose focus.
Showing errors in a separate new window is a bad idea.
You might be able to mitigate this somewhat by setting showactivated false
<Window ...
ShowActivated="False">
Except the user can then click on it.
Or they can click on some other control rather than tabbing away from your custom textbox, for that matter.
Which means depending on retaining focus is probably not a good idea.
You might do better forcing entry of only valid data rather than validating. If this is practical for whatever you're doing.
I have a WinForms application that has a TextBox control (search box) at the top of it. This TextBox is constantly receiving focus during normal application use, and it is very distracting.
I would like the TextBox to only receive the focus if the user explicitly clicks on it.
I can think of a couple rather complicated ways to accomplish this:
Change an image of a text box into a text box when clicked
Keep track of mouse clicks and shift the focus away based on mouse state
Is there something simpler that I can do to accomplish this?
Edit to add better description of problem based on new understanding
Based on the answers that I have received, I now have a bit of a better understanding of what was causing this problem. As the user interacted with my application, various actions would cause controls to either be disabled or to completely disappear. If one of these controls happened to have the focus at the time, then the next control in the tab order would receive the focus.
I don't know what was the "next control" before I added the text box in question. The application has hundreds of controls on screen at any given time, and I'm pretty sure that tab order was never intentionally defined. Whatever it was before, it was innocuous. After adding the search text box, it seemed like that control would always end up with the focus.
Here is a very simple example that demonstrates what was happening:
public class Form1 : Form
{
public Form1()
{
var button = new Button
{
Location = new System.Drawing.Point(159, 67),
Size = new System.Drawing.Size(75, 23),
TabIndex = 0,
Text = #"Click me"
};
button.Click += (sender, args) => button.Enabled = false;
var textBox = new TextBox
{
Location = new System.Drawing.Point(159, 142),
Name = "textBox1",
Size = new System.Drawing.Size(174, 20),
TabIndex = 1
};
SuspendLayout();
ClientSize = new System.Drawing.Size(486, 392);
Controls.Add(textBox);
Controls.Add(_button);
ResumeLayout(false);
PerformLayout();
}
}
After starting the application, clicking on the button will force the text box to get the focus, since it is the next in the tab order. As mentioned by Handbag Crab in the accepted answer, this behavior can be avoided by setting TabStop = false on the text box.
textBox1.TabStop = false;
The above should stop it receiving focus from tabbing.
Subclass the TextBox and over WndProc function to capture the focus message and handle it. Maybe something like this:
if (m.Msg == WM_MOUSEACTIVATE) {
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);
At the moment I have a text box that is bound to a byte property. If the user enters between 0 and 255 the application behaves as expected and the property's setter executes.
However, if the user enters 256 or greater the property's setter does not execute. All that happens is the TextBox becomes outlined in red. I presume this is to indicate that it's an invalid value.
This isn't good enough though. I need to display a messagebox or some note to the user to inform them it's an invalid value. What do I need to do to make this happen?
You need to add a Validation Summary control on the page.
This will be hidden by default, but when the validation error occurs (as in this case when a value greater than 255 is entered) it will appear telling the user what's wrong.
There are several such controls available for WPF, you will need to evaluate them and pick the one that works for you. You will probably need to set some attributes on the data layer to control the exact error message that's displayed.
Another possibility would be to define the TextChanged event of the text box so that it does a Int32.Parse every time the text changes. It can then fire off a message box if the value exceeds 255.
If you want to be mean you can make the maximum length two characters long and force users to input the number in hex.
You can add a validation error handler to the control or window.
In window constructor:
this.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(OnValidationError));
Handler:
private void OnValidationError(Object sender, RoutedEventArgs e)
{
if (e.OriginalSource is DependencyObject)
{
DependencyObject instance = e.OriginalSource as DependencyObject;
if (Validation.GetHasError(instance))
{
System.Collections.ObjectModel.ReadOnlyObservableCollection<ValidationError> errors = Validation.GetErrors(instance);
// todo build message from errors and display
}
}
}
I have an article that covers what you are asking for. The title might not appear to match with what you are asking, but it happens to demo the feature you are asking for.
How to disable a Button on TextBox ValidationErrors in WPF
This will show you how to not only have the red around the TextBox but also how a message too.
Woot, first Stack Overflow post! I've been asked to work on a desktop application to improve an inventory process for my company. I dabbled with WPF in school and I figured I'd start there. After researching some, I learned about MVVM, put a design together, and forged ahead. Finally, I'm stuck and looking for some help and also a sanity check to see if I'm on the right path.
I have single-column DataGrid bound to an observable collection. Users of the application use a scan gun to enter values in. One potential value that I catch in my "Cell" model object is a "MoveNextColumn" value. This raises a custom event in my model that is handled in the View Model. The handler is supposed to simulate blank entries for all remaining rows in that column, set focus on the last row, and wait for input before moving on. So here is what I have so far:
private void dummyCell_MoveToNextColumn(object sender, RoutedEventArgs e) {
e.Handled = true;
// Cell is the model object containing the parsing rules and raising events
var lSender = sender as Cell;
var gridItems = ViewGridReference.Items;
var lastItem = gridItems[gridItems.Count - 1];
if (lSender == lastItem) {
// We are at the bottom of the column
// Move the program on to the next column
CurrentColumn++;
OnPropertyChanged("ItemPositions");
} else {
// Simulate "empty position" input for this cell and all cells down the column
// Cells are validating themselves as the simulation progresses
foreach (Cell item in ViewGridReference.Items) {
item.ActualItemCode = string.Empty;
}
// ViewGridReference is a reference to my DataGrid set from the view
ViewGridReference.Focus();
ViewGridReference.SelectedIndex = gridItems.Count - 1;
ViewGridReference.CurrentCell = new DataGridCellInfo(lastItem, ViewGridReference.Columns[0]);
((DataGridCell)ViewGridReference.SelectedItem).Focus();
}
}
All of this seems to be working as expected: all rows receive blank input and are validated (I use color properties in the cell to which the view binds to signify the validity of the entry).
Unfortunately, though the focus is on the last row as desired, it is not editable and the user cannot submit another "MoveNextColumn" value which would move the program on. The goal here is to minimize any keyboard interaction. Everything should be done with scan guns and barcodes.
Any ideas on how to make the selected cell editable after this code executes?
Any "hey, your design sucks" feedback would be cool too. This is new to me and I'm open to constructive criticism.
I have made some progress with this. The entire grid was left at an uneditable state in the code above. This now leaves focus on the last cell in my column and allows me to submit input with the scan gun.
This seems to work, but I'd still appreciate some feedback on whether there is a better way.
private void dummyCell_MoveToNextColumn(object sender, RoutedEventArgs e) {
e.Handled = true;
// Cell is the model object containing the parsing rules and raising events
var lSender = sender as Cell;
var gridItems = ViewGridReference.Items;
var lastItem = gridItems[gridItems.Count - 1];
if (lSender == lastItem) {
// We are at the bottom of the column
// Move the program on to the next column
CurrentColumn++;
OnPropertyChanged("ItemPositions");
} else {
// Simulate "empty position" input for this cell and all cells down the column
// Cells are validating themselves as the simulation progresses
foreach (Cell item in ViewGridReference.Items) {
item.ActualItemCode = string.Empty;
}
ViewGridReference.SelectedIndex = gridItems.Count - 1;
ViewGridReference.CurrentCell = new DataGridCellInfo(lastItem, ViewGridReference.Columns[0]);
(ViewGridReference.ItemsSource as ListCollectionView).EditItem(ViewGridReference.SelectedItem);
((DataGridCell)ViewGridReference.SelectedItem).Focus();
}
}
Updated 12/2/2010
Hey, there is an important update to this. The first thing to note is that text entry is being done with a scan gun in my scenario, so 'Enter' keys are sent down with each pull of the trigger. It shoots down each character followed by the Enter key all at once.
WPF sees this enter and wants to set the focus to the DataGridCell directly beneath the cell in which the Enter key input was received. The code above sets the focus to the last cell, but then the Enter key event still fires and is handled by DataGrid after this code is run. The effect is that the focus is reset back to the subsequent cell, not the last cell like I want.
So I need to either figure out how to eat the Enter key for just that scan, or I need to break how WPF handles Enter keys. The last line up there actually throws an exception. We are trying to use a Model class (Class.cs) as a DataGridCell, and there is nothing to handle that cast. Because of that, the Focus() method tries to operate on a null object and we get a NullReferenceException. This was really confusing me because Visual Studio 2010 would sometimes break to alert me about this, but sometimes it wouldn't. However, if I run the executable outside of Visual Studio, it works just fine. That's because unhandled, non-fatal exceptions are ignored and the Enter key behavior fails to operate as normal.
So it works, but in a pretty gross way. I either need to figure out how to do one-time handling of the Enter key and override the default WPF handler, or just leave it like it is and grimace.