Wpf Pasting event adds text twice [duplicate] - c#

How can I dynamically change the contents of what will be pasted in the TextBox.
Here is how I subscribe to the event:
DataObject.AddPastingHandler (uiTextBox, TextBoxPaste);
Here is how I define the event handler:
private void TextBoxPaste (object sender, DataObjectPastingEventArgs args)
{
string clipboard = args.DataObject.GetData (typeof (string)) as string;
Regex nonNumeric = new System.Text.RegularExpressions.Regex (#"\D");
string result = nonNumeric.Replace (clipboard, String.Empty);
// I can't just do "args.DataObject.SetData (result)" here.
}

You cannot call args.DataObject.SetData("some data") since the DataObject is frozen. What you can do is replace the DataObject altogether:
private void TextBoxPaste(object sender, DataObjectPastingEventArgs e) {
string text = (String)e.DataObject.GetData(typeof(String));
DataObject d = new DataObject();
d.SetData(DataFormats.Text, text.Replace(Environment.NewLine, " "));
e.DataObject = d;
}

I can think of two ways, none of which are very attractive :) And both ways include canceling the paste command.
The first way would be to cancel the paste command and then calculate what the text would look like after the paste if result was pasted instead.
private void TextBoxPaste(object sender, DataObjectPastingEventArgs args)
{
string clipboard = args.DataObject.GetData(typeof(string)) as string;
Regex nonNumeric = new System.Text.RegularExpressions.Regex(#"\D");
string result = nonNumeric.Replace(clipboard, String.Empty);
int start = uiTextBox.SelectionStart;
int length = uiTextBox.SelectionLength;
int caret = uiTextBox.CaretIndex;
string text = uiTextBox.Text.Substring(0, start);
text += uiTextBox.Text.Substring(start + length);
string newText = text.Substring(0, uiTextBox.CaretIndex) + result;
newText += text.Substring(caret);
uiTextBox.Text = newText;
uiTextBox.CaretIndex = caret + result.Length;
args.CancelCommand();
}
The other way would be to cancel the paste command, change the text in the Clipboard and then re-execute paste. This would also require you to differ between the real paste command and the manually invoked paste command. Something like this
bool m_modifiedPaste = false;
private void TextBoxPaste(object sender, DataObjectPastingEventArgs args)
{
if (m_modifiedPaste == false)
{
m_modifiedPaste = true;
string clipboard = args.DataObject.GetData(typeof(string)) as string;
Regex nonNumeric = new System.Text.RegularExpressions.Regex(#"\D");
string result = nonNumeric.Replace(clipboard, String.Empty);
args.CancelCommand();
Clipboard.SetData(DataFormats.Text, result);
ApplicationCommands.Paste.Execute(result, uiTextBox);
}
else
{
m_modifiedPaste = false;
}
}

I use VB.net quite a bit, I've tested this C# bit, I used a converter because I'm lame :)
string oClipboard;
private void TextBox1_GotFocus(object sender, System.EventArgs e)
{
oClipboard = Clipboard.GetText();
Clipboard.SetText("foo");
}
private void TextBox1_LostFocus(object sender, System.EventArgs e)
{
Clipboard.SetText(oClipboard);
}
I set the clipboard to the new text when the control gets focus. It stores the old value. Later, when the control loses focus, the clipboard is set back to the old value.

Just some modifications of #Fredrik's code, since I've been trying out both of his methods.
First one is just a shortened version
private void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
{
string clipboard = e.DataObject.GetData(typeof(string)) as string;
Regex nonNumeric = new System.Text.RegularExpressions.Regex (#"\D");
string result = nonNumeric.Replace(clipboard, string.Empty);
int caret = CaretIndex;
Text = Text.Substring(0, SelectionStart) + result +
Text.Substring(SelectionStart + SelectionLength);
CaretIndex = caret + result.Length;
e.CancelCommand();
}
and the other one is updated with keeping the clipboard content
private string oldClipboardContent { get; set; } = "";
private bool pasteModified { get; set; } = false;
private void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
{
if (pasteModified)
{
pasteModified = false;
}
else
{
pasteModified = true;
string text = (string)e.DataObject.GetData(typeof(string));
oldClipboardContent = text;
Regex nonNumeric = new System.Text.RegularExpressions.Regex (#"\D");
text = nonNumeric.Replace(text, string.Empty);
e.CancelCommand();
Clipboard.SetData(DataFormats.Text, text);
ApplicationCommands.Paste.Execute(text, this);
Clipboard.SetData(DataFormats.Text, OldClipboardContent);
oldClipboardContent = "";
}
}
I was using those inside my custom TextBox control, that is why I could access TextBox properties without writing the name first.

Related

Combining Two buttons operation into single button in Visual Studio 2019 & C#

I have created a GUI in Visual Studio where I have two buttons. One button is used to show ip and second button is used to take that ip and run python script.
But I want to merge these both operations into only one button, that if clicked for the first time should show/take the ip, and when clicked a 2nd time, it should trigger the Python script and all that in single button click.
My code is:
private void button1_Click(object sender, EventArgs e)
{
var fileName = "C:\\test.txt";
var sr = new StreamReader(fileName);
string fileContent = sr.ReadToEnd();
var startBlock = "hello";
var endBlock = "exit";
var ip = ParseForIpRegex(fileContent, startBlock, endBlock);
myTextBox.Text = ip; //Change this to match your code
}
private readonly string IPV4_PATTERN = "[0-9.]";
private string ParseForIpRegex(string textToSearch, string startBlock, string endBlock)
{
var pattern = $#"{startBlock}\D*\s*({IPV4_PATTERN}+).*{endBlock}";
var ms = Regex.Match(textToSearch, pattern, RegexOptions.Singleline | RegexOptions.IgnoreCase);
if (ms.Groups.Count > 0)
{
return ms.Groups[1].Value;
}
return string.Empty;
}
private void button1_Click_1(object sender, EventArgs e)
{
var hostname = myTextBox.Text;
var username = textBox1.Text;
var password = textBox2.Text;
var psi = new ProcessStartInfo();
psi.FileName = #"C:\Python38\python.exe";
var script = #"C:pythonscript.py";
//var config_file = file_path;
psi.Arguments = $"{script} {hostname} {username} {password}";
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var errors = "";
var results = "";
MessageBox.Show("script processing");
using (var process = Process.Start(psi))
{
errors = process.StandardError.ReadToEnd();
results = process.StandardOutput.ReadToEnd();
}
Console.WriteLine("ERRORS:");
Console.WriteLine(errors);
Console.WriteLine();
Console.WriteLine("Results:");
Console.WriteLine(results);
if (errors != "")
{
MessageBox.Show(errors);
}
else
{
MessageBox.Show(results);
}
}
Please let me know how I can merge this both operation into one. That in one click 1st button operation will perform and after that 2nd in single click.
I suppose you need to keep all buttons, so you dont use args, just call the method:
private void button1_Click(object sender, EventArgs e)
{
//DO job
// simulate the second click
button1_Click_1(sender, e)
}
private void button1_Click_1(object sender, EventArgs e)
{
//you could test args to check if its coming from first button
}
The answer of Frenchy, or you can add 2 handers on the event...
depending your preference.
this.button1.Click += new System.EventHandler(this.button1_Click);
this.button1.Click += new System.EventHandler(this.button1_Click_1);
take note that one of the two the designer will add it for you.
So add the second at form_load event (or where u see fit)
Cheers

How to validate textbox value while user enters and display error message?

So, I have to code for a method that validates whether the string that saves name contains alphabets only, no numbers. The validation of textbox values should apply when the user enters by textchanged event before submitting the form and display an error message of red color on the label. My code works but the problem is when I enter a numeric number in text box, the label displays error which stays even when I delete the text box value and enter the alphabetic string.
I have declared a method which assign error string to label, and is called if regular expression does not match with the text box input, during text changed event.
public void Validator()
{
Calculate_Salary.Enabled = false;
label4.Text = "Please enter only alphabetical letters";
}
private void _Name_TextChanged(object sender, EventArgs e)
{
Regex pattern = new Regex("/^[A-Za-z]+$/");
string name = _Name.Text;
if (pattern.IsMatch(name))
{
Calculate_Salary.Enabled = true;
label4.Text = "";
}
else
{
Validator();
}
}
Just clear the textbox before you validate:
public void Validator()
{
Calculate_Salary.Enabled = false;
label4.Text = "Please enter only alphabetical letters";
}
private void _Name_TextChanged(object sender, EventArgs e)
{
label4.Text = "";
Regex pattern = new Regex("/^[A-Za-z]+$/");
string name = _Name.Text;
if (pattern.IsMatch(name))
{
Calculate_Salary.Enabled = true;
}
else
{
Validator();
}
}
Your Regex comparison is wrong try this code:
public void Validator()
{
Calculate_Salary.Enabled = false;
label4.Text = "Please enter only alphabetical letters";
}
private void _Name_TextChanged(object sender, EventArgs e)
{
label4.Text = "";
string name = _Name.Text;
if (Regex.IsMatch(name, #"^[a-zA-Z]+$"))
Calculate_Salary.Enabled = true;
else
Validator();
}
I changed the validation code. It seems to work now.
private void _Name_TextChanged(object sender, EventArgs e)
{
label4.Text = string.Empty;
string name = _Name.Text;
if (Regex.IsMatch(_Name.Text, "^[a-zA-Z]+$") || _Name.Text=="")
{
Calculate_Salary.Enabled = true;
}
else
{
Calculate_Salary.Enabled = false;
label4.Text = Validator();
}
}

How can I make that the user will be able to search for a multiple texts with textBox?

Today when I type something any text in textBox1 and then click the start button it will search inside files for the text i typed in textBox1.
Now I want to add something somehow that if the user type in the textBox1 for example: hello,hi it will search for hello and also for hi in the files. Not as one string/text but two separated. If I type: hello,hi,world now it will search in same time same files also for hello hi and world.
The textchanged event
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text != "" && textBox3.Text != "" && Directory.Exists(textBox3.Text))
{
startButton.Enabled = true;
Properties.Settings.Default["Setting2"] = textBox1.Text;
Properties.Settings.Default.Save();
}
else
{
startButton.Enabled = false;
}
}
The start button click event
private void startButton_Click(object sender, EventArgs e)
{
label21.Visible = true;
startButton.Enabled = false;
stopButton.Enabled = true;
pauseresumeButton.Enabled = true;
timer1.Start();
if (!backgroundWorker1.IsBusy)
{
SetWorkerMode(true);
backgroundWorker1.RunWorkerAsync();
}
}
Dowork event
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
_stopwatch.Restart();
DirSearch(textBox3.Text, textBox2.Text, textBox1.Text, worker, e);
_stopwatch.Stop();
}
The DirSearch method where I search for the text in files.
void DirSearch(string rootDirectory, string filesExtension, string textToSearch, BackgroundWorker worker, DoWorkEventArgs e)
{
List<string> filePathList = new List<string>();
List<string> restrictedFiles = new List<string>();
int overallfiles = 0;
int numberoffiles = 0;
int numberofdirs = 0;
try
{
filePathList = SearchAccessibleFilesNoDistinct(rootDirectory, null).ToList();
}
catch (Exception err)
{
string ad = err.ToString();
}
foreach (string file in filePathList)
{
try
{
_busy.WaitOne();
if (worker.CancellationPending == true)
{
e.Cancel = true;
return;
}
List<MyProgress> prog = new List<MyProgress>();
int var = File.ReadAllText(file).Contains(textToSearch) ? 1 : 0;
overallfiles++;
if (var == 1)
{
numberoffiles++;
prog.Add(new MyProgress { Report1 = file, Report2 = numberoffiles.ToString() });
backgroundWorker1.ReportProgress(0, prog);
}
numberofdirs++;
label1.Invoke((MethodInvoker)delegate
{
label1.Text = numberofdirs.ToString();
label1.Visible = true;
});
}
catch (Exception)
{
restrictedFiles.Add(file);
continue;
}
}
}
In DirSearch the variable textToSearch contains the text I typed in textBox1.
If I typed in textBox1 only HI so like it is now it will search in each file for the existing of HI.
But if I type HI,HELLO,WORLD
Now I want it to search for existing in each file of HI HELLO WORLD not as one text string but each word on it's own existing.
If I type Hi HELLO WORLD then it will search it as one string/text but once the user put , between it should search each word/text.
You can split the input in the textbox based on space, comma's or any other separator and then pass these as individual inputs to your search method, hope this helps

.Reading and writing to a file from the same textbox

I have a windows form that reads strings from a file and shows them all in a textbox when I press a button.
private void buttonTxt_Click(object sender, EventArgs e)
{
string[] Test = File.ReadAllLines("C:\\testfile.txt");
for (int i = 0; i < testfile.Length; i++)
{
TextBox.Text += testfile[i];
}
}
I'd like to make two radio buttons. So that first button lets my program work the way I described (by default) AND second radio button makes it work vice versa -- so that I could write in a textbox myself and when I press a button it writes a new line to the same file. Is there a way to do it?
Simply add an if statement in this event handler and implement both sending and receiving the data. Done. Sample in principle:
private const string FilePath = #"C:\testfile.txt";
private void buttonTxt_Click(object sender, EventArgs e)
{
if (radioReadMode.Checked) // check which radio button is selected
{ // read mode
string[] Test = File.ReadAllLines(FilePath);
for (int i = 0; i < testfile.Length; i++)
TextBox.Text += testfile[i];
}
else
{ // write mode
File.WriteAllText(FilePath, TextBox.Text);
}
}
I believe this is what you might be looking for. If radio button 1 is checked then if the file exists it will read that file and put it into a textbox in the form. If you switch to radio button 2. You can type in the text box and then when you press the button it will append it to the file.
public partial class Form1 : Form
{
System.IO.StreamReader sr;
System.IO.StreamWriter sw;
public Form1()
{
InitializeComponent();
radioButton1.Checked = true;
}
private void button1_Click(object sender, EventArgs e)
{
if (radioButton1.Checked == true)
{
if (System.IO.File.Exists("C:\\testfile.txt"))
{
try
{
sr = new System.IO.StreamReader("C:\\testfile.txt");
while (!sr.EndOfStream)
{
textBox1.Text += sr.ReadLine() + "\r\n";
}
}
finally
{
sr.Close();
sr.Dispose();
}
}
}
if (radioButton2.Checked == true)
{
if (System.IO.File.Exists("C:\\testfile.txt"))
{
try
{
sw = new System.IO.StreamWriter("C:\\testfile.txt", true);
string result = textBox1.Text;
string[] lststr = result.Split(new Char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in lststr)
{
sw.WriteLine(s);
}
}
finally
{
sw.Flush();
sw.Close();
sw.Dispose();
}
}
}
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
textBox1.Clear();
textBox1.ReadOnly = true;
}
private void radioButton2_CheckedChanged(object sender, EventArgs e)
{
textBox1.Clear();
textBox1.ReadOnly = false;
}
}
Yes, there's a way. Just add another button to your form and inside read the text from the text box this way:
var textBoxContent = TextBox.Text;
and save it to your file this way
File.WriteAllText("C:\\testfile.txt", textBoxContent);
Note: I recommend getting the path to your file into a variable

Getting checkbox tags (in a panel) to new form

Rather new to C# so please forgive me if i am missing something simple or am trying to just do this the wrong way.
I am creating another form to compliment my main form and it needs to pull some of the information from Main form on button click of Second form. The information on the Main for is stored in checkboxes and textboxes.
I have the textboxes working fine but cannot figure out how to pull the checkboxes tag data over along with the formatting. Main Form is working fine as is except I cannot figure out how to bring the checkbox data over as well.
This is the code i currently use to display the checkbox TAG data on my main form.
//Statements to write checkboxes to stringbuilder
string checkBoxesLine = "\u2022 LIGHTS ";
foreach (Control control in pnlCheckBoxes.Controls)
{
if (control is CheckBox)
{
CheckBox checkBox = (CheckBox)control;
if (checkBox.Checked && checkBox.Tag is string)
{
string checkBoxId = (string)checkBox.Tag;
checkBoxesLine += string.Format("{0}, ", checkBoxId);
}
}
}
This is the button i am using to open the new form and move the checkbox tag data and textbox.text data to the new form.
private void code_blue_link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
trouble_shooting = tshooting_text.Text;
services_offered = services_offered_text.Text;
other_notes = other_notes_text.Text;
cust_modem = cust_modem_text.Text;
//Opens CODE BLUE form and pushes text to it.
code_blue_form CBForm = new code_blue_form();
CBForm.cust_name_cb = cust_name_text.Text;
CBForm.cust_cbr_cb = cust_callback_text.Text;
CBForm.cust_wtn_cb = cust_btn_text.Text;
CBForm.cust_notes_cb = cust_modem + "\r\n" + trouble_shooting + "\r\n" + services_offered + "\r\n" + other_notes;
CBForm.Show();
}
Here is my code for the Second form and how i am getting the information to populate textboxes on that form.
public partial class code_blue_form : Form
{
public string cust_name_cb;
public string cust_wtn_cb;
public string cust_cbr_cb;
public string cust_notes_cb;
public string cust_modem_cb;
public code_blue_form()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
cb_name_text.Text = cust_name_cb;
cb_wtn_text.Text = cust_wtn_cb;
cb_cbr_text.Text = cust_cbr_cb;
cb_notes_text.Text = cust_notes_cb;
}
}
}
Please forgive the long post! Any ideas/direction on this would be greatly appreciated. Thanks!
I am not going to answer straight away using ur code. I find code smell. If I were you I would do this (but then if you are adamant about going with the same design, then you can tweak my code accordingly, no big deal, the bottom line is you get the idea how to do):
void code_blue_link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
var checkBoxIds = GetCheckBoxIds();
cust_modem = cust_modem_text.Text;
trouble_shooting = tshooting_text.Text;
services_offered = services_offered_text.Text;
other_notes = other_notes_text.Text;
//take off underscore convetion and replace with camelCase convention.
CodeBlueForm cbForm = new CodeBlueForm(checkBoxIds, cust_name_text.Text,
cust_callback_text.Text,
cust_btn_text.Text,
cust_modem + "\r\n" +
trouble_shooting + "\r\n" +
services_offered + "\r\n" +
other_notes);
cbForm.Show();
}
private List<int> GetCheckBoxIds()//even better naming required like GetFruitIds()
{ //(whatever the id is of) or even better Tag
//checkBoxes with the Fruit object iself and not ids.
List<int> checkBoxIds = new List<int>(); //So you can call GetFruits();
foreach (Control control in pnlCheckBoxes.Controls)
{
if (control is CheckBox)
{
CheckBox checkBox = (CheckBox)control;
if (checkBox.Checked && checkBox.Tag is int) //tag them as ints.
checkBoxIds.Add((int)checkBox.Tag); //I hope ids are integers.
}
}
return checkBoxIds;
}
public partial class CodeBlueForm : Form
{
List<int> checkBoxIds = new List<int>():
string cust_cbr_cb; //should be private.
string cust_name_cb;
string cust_wtn_cb;
string cust_notes_cb;
string cust_modem_cb;
public CodeBlueForm(List<int> ids, string cust_name_cb, string cust_wtn_cb,
string cust_notes_cb, string cust_modem_cb)
{
InitializeComponent();
this.checkBoxIds = ids;
this.cust_name_cb = cust_name_cb;
this.cust_wtn_cb = cust_wtn_cb;
this.cust_notes_cb = cust_notes_cb;
this.cust_modem_cb = cust_modem_cb;
}
private void button1_Click(object sender, EventArgs e)
{
cb_name_text.Text = cust_name_cb;
cb_wtn_text.Text = cust_wtn_cb;
cb_cbr_text.Text = cust_cbr_cb;
cb_notes_text.Text = cust_notes_cb;
string checkBoxesLine = "\u2022 LIGHTS ";
// if you dont require a lot of string formatting, then just:
checkBoxesLine += string.Join(", ", checkBoxIds);
// or go with your classical:
//foreach (int id in checkBoxIds)
// checkBoxesLine += string.Format("{0}, ", checkBoxIds);
//and do what u want with checkboxline here.
}
}

Categories