I would like to develop a textbox which restricts special symbols like %. I used textbox's keydown event to restrict '%' . I already used the code as
if(Keyboard.Modifiers == ModifierKeys.Shift && e.key == key.D5)
{
e.handle=true;
return;
}
when i implement this in mvvm architecture, I got problem with the dependency property that recognizes only shift as one key and D5 as another when I converted systemkey into string format.
How can I recognize % symbol?
you can listen to the PreviewTextInput event instead of the KeyDownEvent :
myTextBox.PreviewTextInput += PreviewTextInputHandler;
and then:
private void PreviewTextInputHandler(Object sender, System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !AreAllValidChars(e.Text);
}
this is one such function I use in my App, you would have to tweak it a bit to test the right caracters, but this you know how to do.
as for getting the % caracter, well you just have to write something like:
if (e.Text == '%') ...;
Related
I have developed a WPF textbox which formats numbers as we keep typing numbers in textbox. This is using interactivity behavior. Now, It works fine with normal regular keyboard. But as we support globalization, textbox should support to Japanese characters(numbers) as well which are full width characters. So to test, when I select Japanese keyboard - Microsoft IME in (windows-controlpanel-region & langauage - keyboard and languages - change keyboards), and enter japanese numbers my interactivity behavior code (hookup) AssociatedObject_PreviewTextInput does not get called until I press 'Enter' Key which creates other issues for me. For regular keyboard, this function gets called as soon I type number.
Code looks as below
private void AssociatedObject_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
TextBox tb = sender as TextBox;
// other stuff
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewTextInput += AssociatedObject_PreviewTextInput;
/// other stuff
}
Any help is appreciated. Thank you.
You can listen to PreviewKeyDown/PreviewKeyUp to get notified for each stroke.
Any you may want to take over input by manipulate TextBox's Text property directly, instead of waiting for the final input after pressing Enter.
AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown;
Here I just handle the case where user is using IME to input digits (0~9). I insert the digit at the caret. And by setting e.Handled = true;, IME will not input anything to the TextBox.
private void AssociatedObject_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.ImeProcessedKey == Key.D0 ||
e.ImeProcessedKey == Key.D1 ||
e.ImeProcessedKey == Key.D2 ||
e.ImeProcessedKey == Key.D3 ||
e.ImeProcessedKey == Key.D4 ||
e.ImeProcessedKey == Key.D5 ||
e.ImeProcessedKey == Key.D6 ||
e.ImeProcessedKey == Key.D7 ||
e.ImeProcessedKey == Key.D8 ||
e.ImeProcessedKey == Key.D9 )
{
TextBox tb = sender as TextBox;
int index = tb.CaretIndex;
//stripe the leading 'D'
string d = e.ImeProcessedKey.ToString().Substring(1);
tb.Text = tb.Text.Insert(index, d);
tb.CaretIndex = index + 1; //I need to manually move the caret forward, since caret position was reset to 0.
e.Handled = true; //important, so IME does not input to the TextBox
}
}
I want to create Style for TextBox so that it only accepts numbers and no characters or special symbols.
Currently I am doing it with the help of back code (in C#) like:
Regex regex = new Regex("[^0-9]+");
e.Handled = regex.IsMatch(e.Text);
Is it possible to make XAML style for handling this scenario?
It's not really possible with XAML only. In my experience, the best thing to do is to derive from TextBox, add handlers to anything that could input text, and then validate the text as it comes in. Either reject the change by handling the event, or accept it by letting the routed event propogate.
A general base class would look like:
public abstract class RestrictedTextBox : TextBox
{
protected RestrictedTextBox()
{
PreviewTextInput += RestrictedTextBox_PreviewTextInput;
}
protected abstract bool IsValid(string proposed);
private void RestrictedTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
string proposed = GetProposedText(e.Text);
if (!IsValid(proposed))
e.Handled = true;
}
private string GetProposedText(string newText)
{
var text = this.Text;
if (SelectionStart != -1)
text.Remove(this.SelectionStart, this.SelectionLength);
return text.Insert(this.CaretIndex, newText);
}
}
To create a concrete instance for, let's say, a DoubleTextBox, you can easily do:
public class DoubleTextBox : RestrictedTextBox
{
protected override bool IsValid(string proposed)
{
double throwAwayDouble;
return double.TryParse(proposed, out throwAwayDouble);
}
}
This will only allow you to input text that successfully parses to a double. I'll leave it to you to handle the keydown-event (for spacebar) and the paste-event
I am trying to implement very simple text formatting functionality for a RichTextBox in WPF. This just consists of a few bold, italic, etc ToggleButtons just above the RichTextBox. See image below, but ignore the top TextBox - the RichTextBox is the bigger one at the bottom.
Toggling formatting for either a selection or at the caret position (for text that will be typed in) is not a problem, as I'm doing this:
private void BoldButton_Checked(object sender, RoutedEventArgs e)
{
this.SetSelectionBold(true);
}
private void BoldButton_Unchecked(object sender, RoutedEventArgs e)
{
this.SetSelectionBold(false);
}
private void SetSelectionBold(bool isBold)
{
var selection = this.RichText.Selection;
if (selection != null)
{
selection.ApplyPropertyValue(TextElement.FontWeightProperty, isBold ? FontWeights.Bold : FontWeights.Normal);
}
}
However, if the user moves the caret somewhere else (e.g. from bold text to normal text) then I'd like the ToggleButtons to reflect that state, in much the same way as it works in Word. Is it possible to detect when the caret position changes, and take action accordingly?
Hook yourself into SelectionChanged event and get current caret position, and test if the property exists on that selection?
In the event, probably you want something like:
var selection = richTextBox.Selection;
if(selection != null)
{
if(selection.GetPropertyValue(TextElement.FontWeightProperty) == FontWeights.Bold)
// todo; enable your button
}
If that event is not triggered by caret positioning(the document doesn't say anything about that),
you probably need to inherit from RichTextBox and override OnSelectionChanged, after that you need to actually generate your own Caret, eg:
var currentCaretPlusOne = new TextRange(richTextBox.CaretPosition,
richTextBox.CaretPosition+1);
if(currentCaretPlusOne != null)
{
if(currentCaretPlusOne.GetPropertyValue(TextElement.FontWeightProperty)
== FontWeights.Bold)
// todo; enable your button
}
I am using C++/CLI Windows Forms Application.
I have a DVG, and I want to deselect rows by clicking blank area of DVG. I tried several ways, and none of them works.
1)
System::Void Form1::dataGridView1_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
if (e->Button == System::Windows::Forms::MouseButtons::Left)
{
if (dataGridView1->HitTest(e->X, e->Y)->Equals(DataGrid::HitTestInfo::Nowhere))
{
dataGridView1->ClearSelection();
}
}
}
2) This variant causes error (Error 1 error C3063: operator '==': all operands must have the same enumeration type)
)
if (e->Button == System::Windows::Forms::MouseButtons::Left)
{
if ((dataGridView1->HitTest(e->X, e->Y)->Type) == DataGrid::HitTestType::None)
{
dataGridView1->ClearSelection();
}
}
The name of your variable is dataGridView1. That implies to me that you're using DataGridView, not DataGrid. You should be using DataGridView::HitTestInfo::Nowhere instead of DataGrid::HitTestInfo::Nowhere, and DataGridViewHitTestType instead of DataGrid::HitTestType.
In your first example, you're comparing a DataGridView::HitTestInfo to DataGrid::HitTestInfo::Nowhere. You're calling the Equals(object, object) method, so it's a valid line of code, but those are different classes that will never return equal, which is why the selection is never getting cleared.
In your second example, you're comparing a DataGridViewHitTestType to a DataGrid::HitTestType, which will generate the compiler error.
My goal is to implement a custom Control + S key press handler to wire up to a custom save method in a winforms app.
There are several ways to accomplish this based on my R&D. First, I tried the obvious KeyPress event handler. This wasn't powerful enough to capture the key presses I need (it wasn't called on the Editor level, which is what I needed).
The second option which looks better is the protected override bool ProcessCmdKey(ref Message msg, Keys keyData) override. This works - it intercepts the CTRL key click, but apparently I need to write extra code to persist the fact the CTRL key is pressed and intercept the next key press (which would be S in my case) and then perform the custom action.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.S | Keys.Control))
{
// This is never called
}
else if (keyData == (Keys.Menu | Keys.Alt))
{
// this is called each time I hit CTRL
}
return true;
}
ProcessCmdKey seems to be called immediately after I hit the CTRL key.
This post suggests creating a KeyTracker class that will persist the keys pressed and do what it needs to do:
Capture Key Sequence via ProcessCmdKey
Which seems like a good option, but before I dig in an implement a memento tracking pattern, does anyone have input on how else to accomplish this seemingly common feature?
Another pattern uses the GetKeyboardState API function:
Capture multiple key downs in C#
This seems interesting, though I'm not sure it will suite my needs.
[DllImport ("user32.dll")]
public static extern int GetKeyboardState( byte[] keystate );
private void Form1_KeyDown( object sender, KeyEventArgs e )
{
byte[] keys = new byte[255];
GetKeyboardState (keys);
if( keys[(int)Keys.Up] == 129 && keys[(int)Keys.Right] == 129 )
{
Console.WriteLine ("Up Arrow key and Right Arrow key down.");
}
}
Thank you for taking a look at my problem.
UPDATE
I've added three events for key handling to my DataPanel. None of these events are being picked up by VS when I set breakpoints in the events, so this is what leads me to believe that ProcessCmdKey is my best option.
If I could get these Events to work, that would be good as well:
// Ctrl + S: Save Support
this.ParentForm.KeyPreview = true;
this.KeyPress += new KeyPressEventHandler(DataPanel_KeyPress);
this.KeyDown += new KeyEventHandler(DataPanel_KeyDown);
this.PreviewKeyDown += new PreviewKeyDownEventHandler(DataPanel_PreviewKeyDown);
None of these events seem to be caught when pressing any keys:
void DataPanel_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == (Keys.S | Keys.Control))
{
SessionManager.Trace.AddTrace("You Hit Save!!");
}
}
void DataPanel_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == (Keys.S | Keys.Control))
{
SessionManager.Trace.AddTrace("You Hit Save!!");
}
}
void DataPanel_KeyPress(object sender, KeyPressEventArgs e)
{
var key = e.KeyChar;
}
UPDATE
I've solved the problem by using a simple KeyUp event and the KeyPreview flag:
void ShipmentDataPanel_KeyUp(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
MessageBox.Show("Control + S Key Hit!");
}
}
Thank you.
Set the KeyPreview property of our form to true. The summary of this property says: "Gets or sets a value indicating whether the form will receive key events before the event is passed to the control that has focus.". Then use the KeyUp event. Unless KeyPressed it gives also information on special keys like control keys.
I solved this by doing,
if(e.KeyData==(Keys.S | Keys.Control))
Though this is a very old question, I still like to add my answer.
The OP writes that he could not use the ProcessCmdKey because it would fire as soon he hits the Control key and would not wait until he hits the S key also.
I don't have that problem, my code below works well and the Delete() method is only called when I first hit Ctrl and then S
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool bHandled = false;
// switch case is the easy way, a hash or map would be better, but more work to get set up.
switch (keyData)
{
case Keys.F5:
RefreshList("", "", false); // call my refresh method
bHandled = true;
break;
case Keys.S | Keys.Control: // call my delete method
Delete(false);
bHandled = true;
break;
default:
base.ProcessCmdKey(ref msg, keyData);
break;
}
return bHandled;
}
protected virtual void Delete(bool handled)
{
if (handled == false)
{
MessageBox.Show("delete");
}
}