I have TextBox which allow insert only numeric values (filtering), But when I paste copied text it's allow any kind of symbol. How can I prevent or filter text before pasting?
You could backup your text before any manual input and then when the input provided isn't valid restore the previous text like so:
_backupText = string.Empty;
doNotPasteTextBox.TextInputStart += (sender, e) =>
{
int textParsed;
if(int.TryParse(e.Text,out textParsed))
{
_backupText = doNotPasteTextBox.Text.Insert(doNotPasteTextBox.SelectionStart, e.Text);
}else
{
e.Handled = true;
}
};
doNotPasteTextBox.TextChanged += (sender, e) =>
{
int textParsed;
int selectionStart = doNotPasteTextBox.SelectionStart;
if(!int.TryParse(doNotPasteTextBox.Text, out textParsed))
{
doNotPasteTextBox.Text = _backupText;
}
doNotPasteTextBox.SelectionStart = selectionStart;
};
I wouldn't recommend trying to capture the control keys or anything because when you're on a mac or on linux then you're screwed.
Adjust my sample and pour it inside a new textbox control to make it cleaner but you get the idea.
You could use Clipboard.GetText() to get the text that is inserted into the textbox, but this will pop up a message, and the user must give the application access to the Clipboard.
If its no problem for you then i would use this.
Related
I have a small problem, I have created a private chat message system using c#. Now what I need is a way to send a clickable link to other person.
When selecting a person from the list, I press invite button and a message comes to the messagebox like "to User1: join from this link"
private void InvBtn_Click(object sender, RoutedEventArgs e)
{
selectedUser = UsersListBox.SelectedItem.ToString();
if (selectedUser != login)
{
MessageBox.Show("Select other user than yourself");
return;
}
else
{
Msg.Text = selectedUser + " join from this 'link' ";
}
}
After sending the other person gets the message to RichTextBox saying
From user2: join from this link
There is no need for open a website, but other other form where will be more details.
You need to create custom MessageBox with Hyperlink button.
Try this out, here u need to set the height and width property properly....and make the constructor to accept the arguments so that users can design it the way they want.
public class CustomMessageBox
{
public CustomMessageBox()
{
Window w = new Window();
DockPanel panel = new DockPanel();
TextBlock tx = new TextBlock();
Paragraph parx = new Paragraph();
Run run1 = new Run("Text preceeding the hyperlink.");
Run run2 = new Run("Text following the hyperlink.");
Run run3 = new Run("Link Text.");
Hyperlink hyperl = new Hyperlink(run3);
hyperl.NavigateUri = new Uri("http://search.msn.com");
tx.Inlines.Add(hyperl);
panel.Children.Add(tx);
w.Content = panel;
w.Show();
}
}
Source : https://social.msdn.microsoft.com/Forums/vstudio/en-US/57fcd28b-6e9e-4529-a583-892c8f6d7cc8/hyperlink-in-wpf-message-box?forum=wpf
First you need to come up with a way to include your special markup in the text message. You can either pack the entire message in an existing container format (XML, JSON, etc.) or to keep things simple include special markers within the text, for example:
Hi User1, join from [This link:12345].
The same way you could include markup for other things like bold (**bold**), italics (*italics*), or actual hyperlinks to websites.
On the other side, you will need a parser that detects this special markup and replaces it with a clickable link. In the following example I'm using Regex to find and replace all text in the format [Text:Command].
private IEnumerable<Inline> Parse(string text)
{
// Define the format of "special" message segments
Regex commandFinder = new Regex(#"\[(?<text>.+)\:(?<command>.+)]");
// Find all matches in the message text
var matches = commandFinder.Matches(text);
// remember where to split the string so we don't lose other
// parts of the message
int previousMatchEnd = 0;
// loop over all matches
foreach (Match match in matches)
{
// extract the text fore it
string textBeforeMatch = text.Substring(previousMatchEnd, match.Index - previousMatchEnd);
yield return new Run(textBeforeMatch);
previousMatchEnd = match.Index + match.Length;
// extract information and create a clickable link
string commandText = match.Groups["text"].Value;
string command = match.Groups["command"].Value;
// it would be better to use the "Command" property here,
// but for a quick demo this will do
Hyperlink link = new Hyperlink(new Run(commandText));
link.Click += (s, a) => { HandleCommand(command); };
yield return link;
}
// return the rest of the message (or all of it if there was no match)
if (previousMatchEnd < text.Length)
yield return new Run(text.Substring(previousMatchEnd));
}
In the method where you receive the message, you can simply integrate it like this:
// Where you receive the text
// This probably is just a `txtOutput.Text += ` until now
private void OnTextReceived(string text)
{
txtOutput.Inlines.AddRange(Parse(text));
}
// the method that gets invoked when a link is clicked
// and you can parse/handle the actual command
private void HandleCommand(string command)
{
MessageBox.Show("Command clicked: " + command);
}
The message Hi User1, join from [this link:1234567890] will show up as Hi User1, join from this link and will invoke HandleCommand("1234567890") when clicked.
This has been an issue with many of my applications and I don't know why Windows doesn't have an elegant solution for this.
I am working with Winforms in .Net 4.5 in VS2013
For example, I would like to change the color of one line of text in a multiline RichTextBox.
For this I am required to set the selection using something like
rtb.Select(rtb.GetFirstCharIndexFromLine(r), str.Length);
Then, I would set the color using
rtb.SelectionColor = Color.Red;
And presumably, cancel the selection with
rtb.DeselectAll();
Now the problem is the cursor/caret has moved back to the beginning of the line,
I try to fix it by saving the previous Caret Position,
rtb.CaretPosition
However, CaretPosition is not a method of RichTextBox, and everywhere online this is the primary method everyone uses.
I tried adding PresentationFramework to my References and to my code I added
using System.Windows.Framework;
As suggested here: http://msdn.microsoft.com/en-us/library/system.windows.controls.richtextbox.caretposition(v=vs.110).aspx
but I still do not see the CaretPosition property, only the ScrollToCaret() method.
My 2 questions are:
How do I get the CaretPosition property in my RichTextBox?
How can I change the text color without using selections and affecting the caret position, having to write complex logic to restore it for the user.
My application checks serial numbers, one per line, and highlights them red if they do not match the format, as shown below.
private void rtb_TextChanged(object sender, EventArgs e)
{
string pattern = #"[A-Z]{2}[A-Z, 0-9]{2}\d{4}";
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
TextReader read = new System.IO.StringReader(rtb.Text);
SerialNumbers.Clear();
int selectStart = 0;
for (int r = 0; r < rtb.Lines.Length; r++)
{
string str = read.ReadLine();
if (str != null)
{
selectStart += str.Length;
MatchCollection matches = rgx.Matches(str);
if (matches.Count == 1)
{
SerialNumbers.Add(str);
}
else
{
rtb.Select(rtb.GetFirstCharIndexFromLine(r), str.Length);
rtb.SelectionColor = Color.Red;
rtb.DeselectAll();
}
}
}
}
You should be using SelectionCaret (as #Mangist mentioned in a comment) because you're using WinForms and not WPF. The MSDN article you referenced only applies to WPF, which is very different from WinForms.
As an example, I use the following to easily log to a rich text box from anywhere in a WinForms app:
public static void Log(string text, ref RichTextBox rtbLogBox) {
//
if (text == null) return;
var timestamp = DateTime.Now.ToLongTimeString();
var logtext = string.Format("{0} - {1}\r\n\r\n", timestamp, text);
if (rtbLogBox.InvokeRequired) {
var logBox = rtbLogBox;
logBox.Invoke(new MethodInvoker(delegate {
logBox.AppendText(logtext);
logBox.Update();
logBox.SelectionStart = logBox.Text.Length;
logBox.ScrollToCaret();
}));
} else {
rtbLogBox.AppendText(logtext);
rtbLogBox.Update();
rtbLogBox.SelectionStart = rtbLogBox.Text.Length;
rtbLogBox.ScrollToCaret();
}
}
Notice how the ScrollToCaret() is called after setting SelectionStart to the length of text in the rich text box. This solves the 'issue' of AppendText not scrolling to the bottom after adding text.
In your case you will simply want to save the SelectionStart value before you format your text with the highlighting, and then restore it once you've finished.
Fixed it by saving SelectionStart position
int selectionStart = SNbox.SelectionStart;
SNbox.Select(SNbox.GetFirstCharIndexFromLine(r), str.Length);
SNbox.SelectionColor = Color.Red;
SNbox.DeselectAll();
SNbox.SelectionStart = selectionStart;
SNbox.SelectionLength = 0;
Im trying to create a TextBox control and force user to enter only numbers in specyfic format there.
How can I do it in WPF?
I have not found any properties like "TextFormat" or "Format" in TextBox class.
I made TextBox like this (not in visual editor):
TextBox textBox = new TextBox();
I want TextBox behavior like in MS Access forms, (user can put only numbers in that textbox in "000.0" format for example).
Consider using WPF's built in validation techniques. See this MSDN documentation on the ValidationRule class, and this how-to.
What you probably need is a masked input. WPF doesn't have one, so you can either implement it yourself (by using validation, for example), or use one of available third-party controls:
FilteredTextBox from WPFDeveloperTools
MaskedTextBox from Extended WPF Toolkit
etc.
Based on your clarification, you want to limit user input to be a number with decimal points.
You also mentioned you are creating the TextBox programmatically.
Use the TextBox.PreviewTextInput event to determine the type of characters and validate the string inside the TextBox, and then use e.Handled to cancel the user input where appropriate.
This will do the trick:
public MainWindow()
{
InitializeComponent();
TextBox textBox = new TextBox();
textBox.PreviewTextInput += TextBox_PreviewTextInput;
this.SomeCanvas.Children.Add(textBox);
}
Meat and potatoes that does the validation:
void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
// change this for more decimal places after the period
const int maxDecimalLength = 2;
// Let's first make sure the new letter is not illegal
char newChar = char.Parse(e.Text);
if (newChar != '.' && !Char.IsNumber(newChar))
{
e.Handled = true;
return;
}
// combine TextBox current Text with the new character being added
// and split by the period
string text = (sender as TextBox).Text + e.Text;
string[] textParts = text.Split(new char[] { '.' });
// If more than one period, the number is invalid
if (textParts.Length > 2) e.Handled = true;
// validate if period has more than two digits after it
if (textParts.Length == 2 && textParts[1].Length > maxDecimalLength) e.Handled = true;
}
I was hoping someone could help with an error check for my paste method. I would like to prevent pasting anything that is not a numeric value from clipboard into my textBox. The coding for pasting is listed below.
private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
{
// Determine if there is any text in the Clipboard to paste into the text box.
if (Clipboard.GetDataObject().GetDataPresent(DataFormats.Text) == true)
{
// Determine if any text is selected in the text box.
if (textBox1.SelectionLength > 0)
{
// Ask user if they want to paste over currently selected text.
if (MessageBox.Show("Do you want to paste over current selection?", "Cut Example", MessageBoxButtons.YesNo) == DialogResult.No)
// Move selection to the point after the current selection and paste.
textBox1.SelectionStart = textBox1.SelectionStart + textBox1.SelectionLength;
} // end if
} // Paste current text in Clipboard into text box.
textBox1.Paste();
} // end pasteToolStripMenuItem
If you want to include Currency symbols, decimal places, Thousand seperators etc. Int.Parse is probably your best bet
public bool IsValidNumber(string input)
{
int val = 0;
return int.TryParse(input.Trim(), NumberStyles.Any, null, out val);
}
"$100,000" = true
"100.002" = true
"1000,44j" = false
etc.
I have this code:
public static void AddDefaultTextFromTag(params TextBox[] textBoxes)
{
foreach (TextBox oTextBox in textBoxes)
{
bool isPasswordChar = oTextBox.UseSystemPasswordChar;
oTextBox.Enter += (sndr, evnt) =>
{
if (((TextBox)sndr).Text == ((TextBox)sndr).Tag.ToString())
{
((TextBox)sndr).Text = "";
((TextBox)sndr).UseSystemPasswordChar = isPasswordChar;
((TextBox)sndr).ForeColor = SystemColors.WindowText;
}
};
oTextBox.Leave += (sndr, evnt) =>
{
if (((TextBox)sndr).Text.Trim().Count() == 0)
{
((TextBox)sndr).UseSystemPasswordChar = false;
((TextBox)sndr).CharacterCasing = CharacterCasing.Normal;
((TextBox)sndr).Text = ((TextBox)sndr).Tag.ToString();
((TextBox)sndr).ForeColor = SystemColors.GrayText;
}
};
if (oTextBox.Text.Trim().Count() == 0)
{
oTextBox.UseSystemPasswordChar = false;
oTextBox.CharacterCasing = CharacterCasing.Normal;
oTextBox.Text = oTextBox.Tag.ToString();
oTextBox.ForeColor = SystemColors.GrayText;
}
}
}
But when the TextBox.UseSystemPasswordChar I input in this method's parameter is true and it's TextBox.Text property is empty, the TextBox can't leave using a Tab button on the keyboard, only a MouseClick can be used to lose the focus of that TextBox.
Why is this happening?
My code is in C#, framework 4, build in VS2010 Pro, project is in WinForms.
I use a TextBox from the VS ToolBox.
Please help. Thanks in advance.
The reason you can't leave the textbox is because you are changing the CharacterCasing property in the textbox.
Not sure why it works like this, but it has happened to me before, what I ended up doing was capture the keypress event, and if it was a letter I'd switch it to it's uppercase value. It's not optimal, but it works
I did something similar to this (writing it from the top of my head, but it should work):
void YourTextbox_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsLetter(e.KeyChar))
{
if (this.CharacterCasing == CharacterCasing.Upper && char.IsLower(e.KeyChar))
{
this.Text = this.Text.Insert(this.SelectionStart, char.ToUpper(e.KeyChar) + string.Empty);
this.SelectionStart++;
e.Handled = true;
}
else if (this.CharacterCasing == System.Windows.Forms.CharacterCasing.Lower && char.IsUpper(e.KeyChar))
{
this.Text = this.Text.Insert(this.SelectionStart, char.ToLower(e.KeyChar) + string.Empty);
this.SelectionStart++;
e.Handled = true;
}
}
}
You also should use the new keyword to "override" (I know that's not the right term here) the Character casing, so it doesn't do it's own thing
public new CharacterCasing CharacterCasing { get; set; }
The code basically checks if the pressed key is a letter, then, if it's marked as Upper, and the char is lower, replaces it with it's upper version (in the position of the cursor) then moves the cursor to the next part, and Viceversa (toLower)
NOTE:
This code will have may (should) have some trouble if the user has more than one character selected (SelectionLenght > 0), if you want to keep the normal Textbox functionality, you should delete all the selected characters
So I set up a WinForms app, drew two textboxes, set one to UseSystemPasswordChar=true then set it up like so:
private void Form1_Load(object sender, EventArgs e)
{
textBox2.Tag = "test2";
textBox1.Tag = "test1";
TextBox[] tb = { textBox1, textBox2 };
AddDefaultTextFromTag(tb);
}
Your function works fine and I have no problems tabbing through the controls on the form no matter what the textboxes contain. (added a button also that does nothing for tabbing test) so... no repro unless my test setup is not valid
What I found in the answer of this post was the solution for me. Instead of setting UseSystemPasswordChar to true and then to false, you can set PasswordChar to '●' and then to '\0' to have normal text. You should not set the UseSystemPasswordChar because it has precedence over PasswordChar.